C# 尝试转换为泛型类型时出错:冗余转换

C# 尝试转换为泛型类型时出错:冗余转换,c#,generics,casting,C#,Generics,Casting,我有一个泛型函数,它返回AnyListVM子类的一个新实例,实现方式基本如下: public TListVM MakeListVM<TListVM>() where TListVM : AnyListVM { TListVM listVM; switch(typeof(TListVM).ToString()) { case nameof(EventListVM):

我有一个泛型函数,它返回
AnyListVM
子类的一个新实例,实现方式基本如下:

    public TListVM MakeListVM<TListVM>()
        where TListVM : AnyListVM
    {
        TListVM listVM;
        switch(typeof(TListVM).ToString())
        {
            case nameof(EventListVM):
                listVM = new EventListVM();
                // some more init stuff
                break;

            // some more similar cases

            default:
                throw new NotImplementedException();
        }
        return listVM;
    }
现在,Visual Studio在我的
新EventListVM()
下面加了下划线,并指出它无法将
EventListVM
隐式转换为
TListVM

public AnyListVM MakeListVM<TListVM>()
    where TListVM : AnyListVM
{
    return MakeListVM(typeof(TListVM)) as TListVM;
}

private AnyListVM MakeListVM(Type listVM)
{
    AnyListVM listVM;
    switch(listVM.ToString())
    {
        case nameof(EventListVM):
            listVM = new EventListVM();
            // some more init stuff
            break;

        // some more similar cases

        default:
            throw new NotImplementedException();
    }
    return listVM;
}
好吧,我想我只是添加了一个显式演员阵容:

        listVM = (TListVM)new EventListVM();
但是没有。现在VisualStudio再次强调它,并说它是一个多余的演员阵容。提供的自动修复方法是再次移除铸件。无限循环


这里出了什么问题,为什么不允许我显式或隐式地执行此强制转换?

您不能保证
EventListVM
将转换为
TListVM
,因为根据您的通用限制,允许传递任何继承的
AnyListVM
类,这些类可能是
EventListVM
。例如,如果此方法的调用方执行以下操作:

AnyListVM vm = MakeListVM<SomeOtherListVMConcrete>();

不过,如果您总是返回一个实例,代码<>事件ListVM< /代码>,我会考虑将泛型子句全部删除并更新签名,以返回一个返回类型<代码>事件ListVM< /COD> .< /P> < P>您不能保证<代码>事件ListVM< <代码>将根据您的通用限制转换为<代码> TListVM < /C>。允许传递任何继承的

AnyListVM
类,该类可以是
EventListVM
。例如,如果此方法的调用方执行以下操作:

AnyListVM vm = MakeListVM<SomeOtherListVMConcrete>();
public AnyListVM MakeListVM<TListVM>()
    where TListVM : AnyListVM
{
    return MakeListVM(typeof(TListVM)) as TListVM;
}

private AnyListVM MakeListVM(Type listVM)
{
    AnyListVM listVM;
    switch(listVM.ToString())
    {
        case nameof(EventListVM):
            listVM = new EventListVM();
            // some more init stuff
            break;

        // some more similar cases

        default:
            throw new NotImplementedException();
    }
    return listVM;
}

但是,如果您总是返回一个实例,代码<>事件ListVM< /代码>,我会考虑将泛型子句全部删除并更新签名,以返回一个返回类型:<代码> Envivistvm < /C> > p> >以使您的问题更加明显,考虑基类和两个子:

public class Base { }           //AnyListVM
public class Child1 : Base{ }   //EventListVM
public class Child2 : Base{ }   //OtherListVM
public AnyListVM MakeListVM<TListVM>()
    where TListVM : AnyListVM
{
    return MakeListVM(typeof(TListVM)) as TListVM;
}

private AnyListVM MakeListVM(Type listVM)
{
    AnyListVM listVM;
    switch(listVM.ToString())
    {
        case nameof(EventListVM):
            listVM = new EventListVM();
            // some more init stuff
            break;

        // some more similar cases

        default:
            throw new NotImplementedException();
    }
    return listVM;
}
现在,您的方法如下所示:

public T Get<T>() where T : Base
{
    //code
    T item = new Child1();
    //more code
}
Child2 item = new Child1();

当然在编译时无效。

为了使问题更加明显,请考虑基类和两个子:

public class Base { }           //AnyListVM
public class Child1 : Base{ }   //EventListVM
public class Child2 : Base{ }   //OtherListVM
现在,您的方法如下所示:

public T Get<T>() where T : Base
{
    //code
    T item = new Child1();
    //more code
}
Child2 item = new Child1();

当然,这在编译时是无效的。

在您的实现中有一个明显的错误,其他人已经指出,但没有令人满意地解决。如果您打算实例化
TListVM
,那么您需要更改两个非常重要的部分。首先是新代码清单:

public TListVM MakeListVM<TListVM>()
    where TListVM : AnyListVM, new()
{
    TListVM listVM = new TListVM();

    EventListVM evtList = listVM as EventListVM;
    if (evtList != null)
    {
        // set evtList properties.  You can't change
        // the instantiation method.
    }

    // repeat for other constructs.

    return listVM;
}

generic helper方法允许您包装更通用的factory方法,使其具有所需的签名,而不会导致编译错误。

在您的实现中有一个明显的错误,其他人已经指出,但没有令人满意地解决。如果您打算实例化
TListVM
,那么您需要更改两个非常重要的部分。首先是新代码清单:

public TListVM MakeListVM<TListVM>()
    where TListVM : AnyListVM, new()
{
    TListVM listVM = new TListVM();

    EventListVM evtList = listVM as EventListVM;
    if (evtList != null)
    {
        // set evtList properties.  You can't change
        // the instantiation method.
    }

    // repeat for other constructs.

    return listVM;
}


泛型帮助器方法允许您包装更泛型的factory方法,使其具有所需的签名,而不会导致编译错误。

没错,但实际上我根据泛型参数决定创建实例的类型,因此创建的对象将始终与泛型类型相匹配
TListVM
。忘了提了。那么你的
MakeListVM
的实际代码与文章中的不同吗?我刚刚编辑了它。我写的几行都是一样的,但周围还有一些。我明白了。谢谢,这更清楚了。然而,答案仍然有效。第一行应将
listVM
变量声明为类型
AnyListVM
,编译器错误将消失。我们可以看到,由于switch语句,
TListVM
始终是您分配的正确类型,但编译器无法推断,因为这是一个运行时解析。但是,我在返回行中得到一个错误,说我无法隐式地将AnyListVM转换为TListVM。那么我必须在那里添加显式转换吗?是的,但实际上我根据泛型参数决定创建实例的类型,因此创建的对象将始终与泛型类型
TListVM
匹配。忘了提了。那么你的
MakeListVM
的实际代码与文章中的不同吗?我刚刚编辑了它。我写的几行都是一样的,但周围还有一些。我明白了。谢谢,这更清楚了。然而,答案仍然有效。第一行应将
listVM
变量声明为类型
AnyListVM
,编译器错误将消失。我们可以看到,由于switch语句,
TListVM
始终是您分配的正确类型,但编译器无法推断,因为这是一个运行时解析。但是,我在返回行中得到一个错误,说我无法隐式地将AnyListVM转换为TListVM。那么我必须在那里添加显式转换吗?奇怪的是,如果我编写
listVM=(TListVM)Activator.CreateInstance(typeof(TListVM))
而不是
listVM=neweventlistVM(),它不符合要求。为什么会这样?语句
listVM=(TListVM)Activator.CreateInstance(typeof(TListVM))
没有对具体类型的引用,因此在这种情况下,编译器永远不必尝试向
EventListVM
或从
EventListVM
强制转换。奇怪的是,如果我编写
listVM=(TListVM)Activator.CreateInstance(typeof(TListVM))
而不是
listVM=neweventlistVM(),它不符合要求。为什么会这样?语句
listVM=(TListVM)Activator.CreateInstance(typeof(TListVM))
没有对具体类型的引用,因此在这种情况下,编译器永远不必尝试在
EventListVM
之间进行强制转换。谢谢,但是有一些数据要作为特定于该类型的初始化传递,因此我仍然需要该开关。如果实现了开关,则需要将不同的配置设置为属性。你不能作为一个构造器。如果是这样的话,泛型是错误的工具。@ByteCommander添加了两个备选方案来满足您的需求,解决泛型的局限性并解决它们。谢谢,