从 PropertyInfo 创建泛型 List<Type>

4

在我的课程中我有以下属性:

public List<ClassP> MyPlanes { get; set; }

另一种方法中,我有一个上面属性的propertyInfo(函数本身不知道propertyinfo来自哪里)。现在我正在尝试在只有MyPlanespropertyInfo的情况下创建classP列表。到目前为止,我的尝试似乎都是徒劳的,这是我到目前为止所做的:

变量prop是MyPlanes的PropertyInfo。

public void GenerateList(PropertyInfo prop)
{
            if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericArguments().Length > 0)
            { 
                List<prop.PropertyType.GetGenericArguments().First()> myValueList = 
                    new List<prop.PropertyType.GetGenericArguments().First()>();
            }
}

使用上面的代码创建列表会出现以下错误:使用通用类型“System.Collections.Generic.List<T>”需要1个类型参数 非常感谢您的帮助。
注意:我想以可见的语法(或类似的语法)创建列表。我希望尽可能地使我的代码通用。

2
注意:我会调用prop.PropertyType.GetGenericArguments()只一次,并缓存结果。我相信这是一个耗费资源的操作。 - Matt Burland
@MattBurland 感谢您的提示! - User999999
2个回答

4
为了在你有类型时制作一个通用类,你不能使用尖括号<>,因为你在编译时不知道类型。你需要像这样做:
var baseType = typeof(List<>);
var genericType = baseType.MakeGenericType(prop.PropertyType.GetGenericArguments().First());

现在您已经获得了正确的类型,可以像这样创建它:

IList myList = (IList)Activator.CreateInstance(genericType);

编辑:正如Selman22在上面所说,您已经有了PropertyType,因此除非您试图使用相同的泛型参数创建不同的泛型类(例如,您拥有一个List<T>并需要创建一个Dictionary<Type,T>或其他类似的情况),否则您不需要获取通用类型。 因此,我将保留我的答案以防您遇到这种情况。


有没有办法在不在定义中明确提到 ClassP 的情况下提取(在我的情况下)List<ClassP>?如果可以,我是否保留了 List 的所有功能(我主要关注 Add() 函数)? - User999999
我对你的代码进行了小改动以代表我的工作代码。感谢你的帮助!!! - User999999
@Knorriemans:哎呀,抱歉,在看到你的评论之前我已经回滚了。我(认为)已经恢复了它。 - Matt Burland
一个不错的还原 :) 。现在我可以创建通用列表(在这种情况下为iList),因为这正是我所期望的! - User999999
@Knorriemans:请注意,虽然您可以使用“Add”,但它不会是类型安全的。如果您向“Add”传递了错误类型的对象,将会出现运行时异常。 - Matt Burland
Add 的检查已经存在。因为在设置属性时总是会进行检查 :) - User999999

2

不幸的是,它并不像那样工作。您需要使用Reflection来创建一个新实例:

var list = (List<ClassP>)Activator.CreateInstance(prop.PropertyType);
CreateInstance 方法返回一个 object 对象。如果你在编译时不知道类型,就无法进行强制转换。最好的方法是使用dynamic。这样,你可以访问任何成员,而不会出现编译时错误,但显然这是不安全的。
你应该重新考虑是否真的需要在这里使用Reflection。如果你的问题可以在不使用Reflection的情况下解决,那么你应该选择这种方式。

让我说,反射是可取的而非强制性的。但我担心我的目标会很难实现。我会研究一下dynamic类型。也许我可以增强我的类以防止那些编译错误。 - User999999
基于这个想法,您可以使用prop.SetValue将属性设置为您创建的新列表,即public void InitPropertyValue(PropertyInfo prop,object instance) { prop.SetValue(instance,Activator.CreateInstance(prop.PropertyType)); } 其中instance是具有MyPlanes属性的类型的实例。 - Grax32

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接