昨晚我了解了casting by example的这个精彩操作:使用对现有实例的引用生成某些Type集合的一种非常酷的方法。
我的问题是,虽然这在显式创建实例时有效,但如果使用激活器从类型实例化,则生成的集合类型不准确。
class TestCollectionContent
{
public int id { get; private set; }
}
[Test]
public void TestListCastCreation()
{
var explicitCast = new TestCollectionContent (); //This casts as TestCollectionContent
var explicitList = MakeList (explicitCast); //This casts as List<CommandWithExecute>
explicitList.Add (new TestCollectionContent ());
Type clazz = typeof(TestCollectionContent);
var implicitCast = Activator.CreateInstance (clazz);//This casts as TestCollectionContent
var implicitList = MakeList (implicitCast); //This casts as List<object>
implicitList.Add (new TestCollectionContent ());
Assert.AreEqual (explicitCast.GetType (), implicitCast.GetType ()); //Succeeds
Assert.AreEqual (explicitList.GetType (), implicitList.GetType ()); //FAILS!
}
public static List<T> MakeList<T>(T itemOftype)
{
List<T> newList = new List<T>();
return newList;
}
为了我的目的,必须正确地收集集合。有什么想法吗?
请注意,我正在使用带有Unity3D的C#(它使用的东西类似于.Net 3.5)。
答案 0 :(得分:1)
Activator.CreateInstance
始终返回object
,因此在使用时不会从中获取任何静态类型信息。这将使implicitCast
类型的变量object
,尽管它的值是更专业的类型。
现在使用泛型时,只考虑可用于静态类型的类型。因此,在将implicitCast
传递给MakeList
时,所有方法都会看到object
。因此,该方法将被称为MakeList<object>
,并将返回List<object>
,其当然与explicitList
的类型不同。
不幸的是(或幸运的是?)你真的不能做得更好。泛型应该是在静态类型环境中使用的东西,如果你开始动态创建类型,你将失去这种能力。
然而,您可以通过执行以下操作来使用Activator.CreateInstance
创建列表:
public static IList MakeList(object itemOftype)
{
Type listType = typeof(List<>).MakeGenericType(itemOfType.GetType());
return (IList) Activator.CreateInstance(listType);
}
当然,这也只会返回一个对象,因此您必须将其转换为更专业的类型,或者使用非通用IList
接口至少具有一些访问权限。
答案 1 :(得分:0)
此代码的行为方式是因为T
在编译时是inferred,而不是运行时。由于implicitCast
的类型为object
,因此会使用MakeList<object>
进行编译。
var implicitList = MakeList (implicitCast); // equivalent to
List<object> implicitList = MakeList<object>(implicitCast);
var explicitList = MakeList (explicitCast); // equivalent to
List<TestCollectionContent> explicitList =
MakeList<TestCollectionContent>(explicitCast);
如果您希望它使用运行时类型,您可以使用反射或dynamic
。