不能将通过反射创建的类添加到容器



我正在编写一些涉及一些讨厌的反射黑客的代码。目前,我正在创建一个类的实例以及该类的List<T>容器,其中使用的类由字符串确定。到目前为止,所有内容都包含在同一个程序集中。

Type containerType = typeof(List<>);
Assembly currentAsm = Assembly.GetExecutingAssembly();
Type applicationModelType = currentAsm.GetType("NamespaceName." + targetApplicationModel);
Type applicationModelContainerType = containerType.MakeGenericType(applicationModelType);
dynamic container = Activator.CreateInstance(applicationModelContainerType);

在本例中,targetApplicationModel是一个字符串,包含用于列表的对象和泛型部分的类的名称。现在我想创建一个该类型的实例并将其添加到容器中:

var x = Activator.CreateInstance(applicationModelType);
container.Add(y);
var y = container.Item[0];

呼叫Add失败
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in System.Core.dll
An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll
The best overloaded method match for 'System.Collections.Generic.List<MyType>.Add(MyType)' has some invalid arguments

我可以相当肯定地检查,而调试x确实是MyType的一个实例,所以我不知道为什么调用失败。

跟进我的"不要使用dynamic"发表评论。我做了以下操作:

首先我创建了一个虚拟类:

public class ClassToCollect
{
public string SomeProperty { get; set; } = "Hello World";
}

然后我运行这段代码:

var containerType = typeof(List<>);
var itemType = typeof(ClassToCollect);
var fullContainerType = containerType.MakeGenericType(itemType);
var container = Activator.CreateInstance(fullContainerType);
var addMethod = fullContainerType.GetMethod("Add");
var objectToAdd = Activator.CreateInstance(itemType);
addMethod.Invoke(container, new object[] { objectToAdd });

在代码的末尾,我可以看到列表中的一个项目。

只要是在";"上,就不要使用dynamic&;踢,我喜欢扔一个"不要使用Activator.CreateInstance";方法,因为与调用构造函数相比,它的传统性能非常差(最近的。net版本已经修复了很多,但仍然)。为了避免一些令人讨厌的反射,通常应该像"通常"那样编写代码,然后只在最后一步动态调用它。

static List<T> createSingleElementList<T>() where T : new() => new() { new() };
Type applicationModelType = ...;
object container = ((Func<List<object>>) createSingleElementList<object>)
.Method
.GetGenericMethodDefinition()
.MakeGenericMethod(applicationModelType)
.Invoke(null, null);

这段代码使用了只有新版本的c#才有的各种特性(静态局部方法,隐式类型的new),但这些都不重要;如果您愿意,您可以用其他方式编写createSingleElementList。核心技术是从函数中提取泛型方法,并在运行时使用所需的类型调用该方法。在这种特殊情况下,我们并没有从这样写东西中获得多少好处,但是你可以想象createSingleElementList要复杂得多,这将导致一长串动态调用,如果我们只使用反射来写,就不再清楚发生了什么。

撇开类型安全不谈,即使这不是绝对最快的方法,但优化动态代码完全是另一个问题。

最新更新