给定 Array.Cast<T>(),如何通过反射确定 T?
Given Array.Cast<T>(), how do I determine T via reflection?
TL;DR - 我希望所有这些都能以相同的方式工作,但(根据评论)它们不会:
var c1 = new[] { FileMode.Append }.Cast<int>();
var c2 = new[] { FileMode.Append }.Select(x => (int)x);
var c3 = new[] { FileMode.Append }.Select(x => x).Cast<int>();
foreach (var x in c1 as IEnumerable)
Console.WriteLine(x); // Append (I would expect 6 here!)
foreach (var x in c2 as IEnumerable)
Console.WriteLine(x); // 6
foreach (var x in c3 as IEnumerable)
Console.WriteLine(x); // 6
这是一个人为的例子;如果没有必要,我显然不会将集合转换为 IEnumerable
,在那种情况下,一切都会按预期进行。但是我正在使用多种方法开发一个库,这些方法采用 object
和 return 序列化字符串表示形式。如果它通过反射确定对象实现了 IEnumerable
,它将枚举它,并且在几乎所有情况下,return 预期结果......除了 Array.Cast<T>
的这种奇怪情况。
我可以在这里做两件事:
- 告诉用户首先具体化
IEnumerable
,例如 ToList()
。
- 为每个采用
IEnumerable<T>
. 的受影响方法创建重载
出于不同的原因,这些都不是理想的。当传递 Array.Cast<T>()
时,采用 object
的方法是否有可能以某种方式推断出 T
?
Is it possible for a method that takes an object to somehow infer T when Array.Cast() is passed?
不,你举的例子中没有。
您获得输出的原因是 Enumerable.Cast<T>()
方法进行了优化,允许在与您要求的类型兼容时返回原始对象:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
if (typedSource != null) return typedSource;
if (source == null) throw Error.ArgumentNull("source");
return CastIterator<TResult>(source);
}
所以在你的第一种情况下,实际上什么都没有发生。 Cast<T>()
方法只是返回您传递给该方法的对象,因此当您取回它时,它曾经经历过 Cast<T>()
的事实已完全丢失。
你的问题没有任何其他细节说明你是如何陷入这种情况的,或者它在实际意义上为什么重要。但我们可以断定地说,鉴于您发布的代码,不可能实现您所说的目标。
TL;DR - 我希望所有这些都能以相同的方式工作,但(根据评论)它们不会:
var c1 = new[] { FileMode.Append }.Cast<int>();
var c2 = new[] { FileMode.Append }.Select(x => (int)x);
var c3 = new[] { FileMode.Append }.Select(x => x).Cast<int>();
foreach (var x in c1 as IEnumerable)
Console.WriteLine(x); // Append (I would expect 6 here!)
foreach (var x in c2 as IEnumerable)
Console.WriteLine(x); // 6
foreach (var x in c3 as IEnumerable)
Console.WriteLine(x); // 6
这是一个人为的例子;如果没有必要,我显然不会将集合转换为 IEnumerable
,在那种情况下,一切都会按预期进行。但是我正在使用多种方法开发一个库,这些方法采用 object
和 return 序列化字符串表示形式。如果它通过反射确定对象实现了 IEnumerable
,它将枚举它,并且在几乎所有情况下,return 预期结果......除了 Array.Cast<T>
的这种奇怪情况。
我可以在这里做两件事:
- 告诉用户首先具体化
IEnumerable
,例如ToList()
。 - 为每个采用
IEnumerable<T>
. 的受影响方法创建重载
出于不同的原因,这些都不是理想的。当传递 Array.Cast<T>()
时,采用 object
的方法是否有可能以某种方式推断出 T
?
Is it possible for a method that takes an object to somehow infer T when Array.Cast() is passed?
不,你举的例子中没有。
您获得输出的原因是 Enumerable.Cast<T>()
方法进行了优化,允许在与您要求的类型兼容时返回原始对象:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
if (typedSource != null) return typedSource;
if (source == null) throw Error.ArgumentNull("source");
return CastIterator<TResult>(source);
}
所以在你的第一种情况下,实际上什么都没有发生。 Cast<T>()
方法只是返回您传递给该方法的对象,因此当您取回它时,它曾经经历过 Cast<T>()
的事实已完全丢失。
你的问题没有任何其他细节说明你是如何陷入这种情况的,或者它在实际意义上为什么重要。但我们可以断定地说,鉴于您发布的代码,不可能实现您所说的目标。