通用工厂方法来创建通用类型的输入和输出

时间:2017-08-07 16:04:05

标签: c# generics

我有以下实现生成编译器错误

  

“无法将类型'ParentMenuItemFilter'隐式转换为   'IMenuItemFilter<MenuItem>'。存在显式转换(是你   错过演员?)

public class MenuItem
{
    // implementation removed for clarity
}

public class ParentMenuItem : MenuItem
{
    // implementation removed for clarity
}

public interface IMenuItemFilter<TMenuItemType>
        where TMenuItemType : MenuItem
{
    TMenuItemType ApplySecurity(TMenuItemType menuItem);
}


public class ParentMenuItemFilter : IMenuItemFilter<ParentMenuItem>
{
    public ParentMenuItem ApplySecurity(ParentMenuItem menuItem)
    {
        // implementation removed for clarity
    }
}

public class MenuItemFilterFactory
{
    public IMenuItemFilter<MenuItem> Create<TMenuItemType>(TMenuItemType menuItem)
            where TMenuItemType : MenuItem
    {
        if (typeof(TMenuItemType) == typeof(ParentMenuItem))
        {
            // here is the errored line!...
            return new ParentMenuItemFilter(this);
        }
        else if (/* create some other types*/)
        {
            ...
        }
    }
}

所以我的两个最好的朋友,协方差和逆变进来。我希望通过通用工厂方法实现上述目标,该方法将返回IMenuItemFilter的相应实例,该实例将对menuItem Create参数执行操作方法。

我想将MenuItem实例传递给工厂方法以便解决此问题。

我尝试在界面和其他定义中输入和输出in TMenuItemTypeIn, out TMenuItemTypeOut - 无济于事。我在Stack Exchange上将其发布到CodeReview时是50/50,但认为这同样是编码问题以及代码设计问题。我今天花了大部分时间试图让这个工作起作用,但是有很多中断。

2 个答案:

答案 0 :(得分:2)

如果这不是一个过于简单的例子,那么每个类型实际上应该有一个方法,例如: CreateParentMenuItemFilter或类似的东西。你的通用方法似乎只会使事情变得复杂而没有任何好处。

答案 1 :(得分:1)

我想你需要的只是public interface IMenuItemFilter<out TMenuItemType>。但是有一个基于泛型类型参数执行不同操作的泛型方法有点奇怪而不是泛型的意图 - 这就是为什么它们被称为泛型:它们对不同的类做同样的事情

所以我建议你的工厂不通用:

public class MenuItemFilterFactory
{
    public IMenuItemFilter Create(MenuItem menuItem)
    {
        if (menuItem.GetType() == typeof(ParentMenuItem))
        {
            return new ParentMenuItemFilter(this);
        }
        else if (/* create some other types*/)
        {
            ...
        }
    }
}

然而,假设您拥有非通用版本的接口,通用版本也是如此:

public interface IMenuItemFilter
{
}
public interface IMenuItemFilter<TMenuItemType> : IMenuItemFilter
        where TMenuItemType : MenuItem
{
    TMenuItemType ApplySecurity(TMenuItemType menuItem);
}