从另一个 IEnumerable 填充任意具体的 IEnumerable
Populate an arbitrary concrete IEnumerable, from another IEnumerable
我正在写一些反射代码。呃,好吧。
我有一个 IEnumerable<TData>
值对象,和一个 Expression<Func<TInstance, IEnumerable<TData>>>
代表一个 属性 其类型实现(但不是 声明 作为)IEnumerable<TData>
.
例如我有一个 属性 声明为:
public SomeProp List<String> {get;set;}
、值对象 new[] {"a", "bee", "sea"}
和表达式 obj => obj.SomeProp
提取信息的代码我写成功了:
the concrete implementation of IEnumerable<>
for SomeProp
is List<>
因此我可以在我的 IEnumerable<string>
值对象上调用 values.ToList()
并将结果成功分配给 属性.
对于 IEnumerable<>
的任何特定实现,我可以手动编写代码来检测该实现,并编写代码来创建满足它的具体对象。
事实上,我目前有一个小型映射字典,涵盖了一些情况:
new Dictionary<Type, Func<IEnumerable<TProp>, IEnumerable<TProp>>>
{
{ typeof(List<>), (vals) => vals.ToList() },
{ typeof(IList<>), (vals) => vals.ToList() },
{ typeof(Collection<>), (vals) => new Collection<TProp>(vals.ToList()) },
{ typeof(ICollection<>), (vals) => new Collection<TProp>(vals.ToList()) },
};
当然,这甚至没有涵盖大多数常见情况,更不用说涵盖所有可能的情况了!
有什么方法可以编写反射代码来获取任意 "values" IEnumerable<T>
和目标具体 IEnumerable<T>
,并从中创建具体实例值?
似乎有点乐观,但我认为值得一问:)
TL;DR: 在一般情况下,这是不可能的。最后,这只是接口不能直接构造的问题。
在 .NET 框架类型中
如果您的目标类型确实是像 List<>
或 Collection<>
这样的具体类型,那么就可以从其 Type
对象中创建一个实例。您仍然必须假设存在一个接受 IEnumerable<T>
作为第一个也是唯一一个参数的构造函数。即使使用常见的框架类型也不是这种情况:
Type[] types = { typeof(List<string>), typeof(IList<string>), typeof(Collection<string>), typeof(ICollection<string>) };
IEnumerable<T> values = new List<T> { /* ... */ };
foreach (var type in types) {
var concreteInstance = type.GetConstructor(new Type[] { typeof(IEnumerable<T>) })?.Invoke(new object[] { values });
// Succeeds for List<>.
// Fails for IList<> as not a concrete type.
// Fails for Collection<> as no constructor accepts IEnumerable as first argument.
// Fails for ICollection as not a concrete type.
}
一般情况
让我们定义以下接口:
interface IArbitrary<T> : IEnumerable<T> { }
事实上,目前还没有这个接口的具体实现。因此,无论您多么努力地尝试,都无法使用反射代码创建 "target concrete IArbitrary<T>
from an IEnumerable<T>
"。
我正在写一些反射代码。呃,好吧。
我有一个
IEnumerable<TData>
值对象,和一个 Expression<Func<TInstance, IEnumerable<TData>>>
代表一个 属性 其类型实现(但不是 声明 作为)IEnumerable<TData>
.
例如我有一个 属性 声明为:
public SomeProp List<String> {get;set;}
、值对象 new[] {"a", "bee", "sea"}
和表达式 obj => obj.SomeProp
提取信息的代码我写成功了:
the concrete implementation of
IEnumerable<>
forSomeProp
isList<>
因此我可以在我的 IEnumerable<string>
值对象上调用 values.ToList()
并将结果成功分配给 属性.
对于 IEnumerable<>
的任何特定实现,我可以手动编写代码来检测该实现,并编写代码来创建满足它的具体对象。
事实上,我目前有一个小型映射字典,涵盖了一些情况:
new Dictionary<Type, Func<IEnumerable<TProp>, IEnumerable<TProp>>>
{
{ typeof(List<>), (vals) => vals.ToList() },
{ typeof(IList<>), (vals) => vals.ToList() },
{ typeof(Collection<>), (vals) => new Collection<TProp>(vals.ToList()) },
{ typeof(ICollection<>), (vals) => new Collection<TProp>(vals.ToList()) },
};
当然,这甚至没有涵盖大多数常见情况,更不用说涵盖所有可能的情况了!
有什么方法可以编写反射代码来获取任意 "values" IEnumerable<T>
和目标具体 IEnumerable<T>
,并从中创建具体实例值?
似乎有点乐观,但我认为值得一问:)
TL;DR: 在一般情况下,这是不可能的。最后,这只是接口不能直接构造的问题。
在 .NET 框架类型中
如果您的目标类型确实是像 List<>
或 Collection<>
这样的具体类型,那么就可以从其 Type
对象中创建一个实例。您仍然必须假设存在一个接受 IEnumerable<T>
作为第一个也是唯一一个参数的构造函数。即使使用常见的框架类型也不是这种情况:
Type[] types = { typeof(List<string>), typeof(IList<string>), typeof(Collection<string>), typeof(ICollection<string>) };
IEnumerable<T> values = new List<T> { /* ... */ };
foreach (var type in types) {
var concreteInstance = type.GetConstructor(new Type[] { typeof(IEnumerable<T>) })?.Invoke(new object[] { values });
// Succeeds for List<>.
// Fails for IList<> as not a concrete type.
// Fails for Collection<> as no constructor accepts IEnumerable as first argument.
// Fails for ICollection as not a concrete type.
}
一般情况
让我们定义以下接口:
interface IArbitrary<T> : IEnumerable<T> { }
事实上,目前还没有这个接口的具体实现。因此,无论您多么努力地尝试,都无法使用反射代码创建 "target concrete IArbitrary<T>
from an IEnumerable<T>
"。