Wil*_*ill 2 c# reflection activator
我正在使用Activator.CreateInstance类型变量创建对象(在运行时未知):
static dynamic CreateFoo( Type t ) =>
Activator.CreateInstance( t );
Run Code Online (Sandbox Code Playgroud)
显然,我还没有正确理解如何使用该dynamic类型,因为这仍然只是返回一个对象.
我需要能够将一个集合传递给另一个调用,Activator.CreateInstance在那里创建的类型可能是List<T>:
var values = Enumerable.Range( 1, 50 ).Select(
I => CreateFoo( typeof( Foo ) ) ).ToArray( );
//This will explode.
var foobar = Activator.CreateInstance(
typeof( List<Foo> ), values );
Run Code Online (Sandbox Code Playgroud)
调用上面的内容时,它会爆炸,但会出现以下异常:
我明白为什么它这样做 - 当列表使用类型参数定义时,没有列表的构造函数期望可枚举的对象.
问题是我无法转换对象,因为我不知道运行时的类型.Activator.CreateInstance只是似乎返回一个对象,这对List<Foo>我来说很好,因为我将使用依赖对象和属性设置它们,所以盒装对象对他们来说完全没问题,但在尝试创建列表时会破坏一切(可能还有什么否则与构造函数期望类型参数).
我想在这里做什么的正确方法是什么?
符合最小,完整和可验证的示例要求:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MCVEConsole {
class Program {
static int Main( string[ ] args ) {
var values = Enumerable.Range( 1, 50 ).Select(
I => CreateFoo( typeof( Foo ) ) ).ToArray( );
//This will compile, but explode when run.
var foobar = Activator.CreateInstance(
typeof( List<Foo> ), values );
return 1;
}
static dynamic CreateFoo( Type t ) =>
Activator.CreateInstance( t );
}
class Foo {
public Foo( ) { }
}
}
Run Code Online (Sandbox Code Playgroud)
Nin*_*rry 16
使用这种方法:
class Program
{
static void Main(string[] args)
{
CreateListFromType(typeof(Foo));
CreateListFromType(typeof(int));
}
static object CreateListFromType(Type t)
{
// Create an array of the required type
Array values = Array.CreateInstance(t, 50);
// and fill it with values of the required type
for (int i = 0; i < 50; i++)
{
values.SetValue(CreateFooFromType(t), i);
}
// Create a list of the required type, passing the values to the constructor
Type genericListType = typeof(List<>);
Type concreteListType = genericListType.MakeGenericType(t);
object list = Activator.CreateInstance(concreteListType, new object[] { values });
// DO something with list which is now an List<t> filled with 50 ts
return list;
}
// Create a value of the required type
static object CreateFooFromType(Type t)
{
return Activator.CreateInstance(t);
}
}
class Foo
{
public Foo() { }
}
Run Code Online (Sandbox Code Playgroud)
这种情况下没有必要使用dynamic。我们只能利用object我们创造的价值。非引用类型将存储在objectusing 装箱中。
为了创建List<>类型,我们可以首先获取泛型类型的表示,然后使用该表示来使用该MakeGenericType方法创建具体类型。
当尝试构造列表时,您需要将值数组作为元素嵌入到对象数组中。因此,它将Activator寻找List<t>一个需要类型为单个参数的构造函数IEnumerable<t>。
按照您编写的方式,它Activator会查找需要 50 个参数的构造函数,每个参数的类型为 t。
using System.Collections;
static IList CreateListFromType(Type t)
{
// Create a list of the required type and cast to IList
Type genericListType = typeof(List<>);
Type concreteListType = genericListType.MakeGenericType(t);
IList list = Activator.CreateInstance(concreteListType) as IList;
// Add values
for (int i = 0; i < 50; i++)
{
list.Add(CreateFooFromType(t));
}
// DO something with list which is now an List<t> filled with 50 ts
return list;
}
Run Code Online (Sandbox Code Playgroud)
static void Main(string[] args)
{
CreateListFromType(typeof(List<Foo>));
CreateListFromType(typeof(ObservableCollection<int>));
}
static IList CreateListFromType(Type listType)
{
// Check we have a type that implements IList
Type iListType = typeof(IList);
if (!listType.GetInterfaces().Contains(iListType))
{
throw new ArgumentException("No IList", nameof(listType));
}
// Check we have a a generic type parameter and get it
Type elementType = listType.GenericTypeArguments.FirstOrDefault();
if (elementType == null)
{
throw new ArgumentException("No Element Type", nameof(listType));
}
// Create a list of the required type and cast to IList
IList list = Activator.CreateInstance(listType) as IList;
// Add values
for (int i = 0; i < 50; i++)
{
list.Add(CreateFooFromType(elementType));
}
// DO something with list which is now a filled object of type listType
return list;
}
Run Code Online (Sandbox Code Playgroud)
显然,我还没有正确理解如何使用动态类型,因为这仍然只是返回一个对象.
是的,你不明白. 只不过dynamic是带着花哨的帽子的对象.返回类型dynamic表示"我返回object,但调用者应该允许对返回的对象进行操作object,这些操作通常不会被允许,并且这些操作将在运行时解析".
如果那不是你的意思,那就不要用了dynamic.
我明白为什么它这样做 - 当列表使用类型参数定义时,没有列表的构造函数期望可枚举的对象.
正确.在你的代码中:
var values = Enumerable.Range( 1, 50 ).Select(
I => CreateFoo( typeof( Foo ) ) ).ToArray( );
Run Code Online (Sandbox Code Playgroud)
values是dynamic[],这又是刚刚object[]与滑稽的帽子.因此,您正在调用构造函数,List<Foo>而object[]不是IEnumerable<Foo>根据需要调用构造函数.
我想在这里做什么的正确方法是什么?
在适当的做的事情就是停止使用静态类型语言做动态类型的工作,但我怀疑这将是一个非首发.
你有一个object[].你需要的是一个t[]地方t是通过反射提供的类型. 使用Reflection的问题的解决方案几乎总是使用更多的Reflection.那样做吧.不要这样做:
var values = Enumerable.Range( 1, 50 ).Select(
I => CreateFoo( typeof( Foo ) ) ).ToArray( );
Run Code Online (Sandbox Code Playgroud)
这不足以使用反射.做这个:
object foos = Array.CreateInstance(typeof(Foo), 50);
Run Code Online (Sandbox Code Playgroud)
大.现在你有了一个Foo[50],你可以使用反射再次填充它,或者dynamic使用动态运行时来调度数组索引; 我假设你可以编写该代码.如果你不能,请问另一个问题.
现在你有一个充满Foo[]是IEnumerable<Foo>,然后你就可以传递给List<Foo>构造函数.
为什么你会这样做 - 创建一个Foo[]获得一个IEnumerable<Foo>与我List<Foo>相同的内容Foo[]- 我不知道.对于没有构造函数的参数并直接填充它的更简单的步骤,这似乎是太多的步骤List<Foo>()!但这就是你问的问题,所以这个问题得到了回答.
这听起来很像我们称之为"XY问题".你对如何解决你的问题有一些疯狂的想法,你问的是疯狂的想法,而不是询问问题,所以答案有点疯狂.什么是真正的问题?
| 归档时间: |
|
| 查看次数: |
678 次 |
| 最近记录: |