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添加了两个备选方案来满足您的需求,解决泛型的局限性并解决它们。谢谢,