指定隐式转换时,IEnumerable Cast <t> InvalidCastException

时间:2019-05-14 17:43:22

标签: c# linq casting

我试图了解Enumerable.Cast执行强制转换的原因,以及为什么即使为目标类型定义了隐式(或显式)转换运算符也无法使其正常工作。

>

以下代码组合了一些我已经准备了解错误原因的测试。我真正想要的是了解为什么test5抛出而InvalidCastException抛出;但是在现阶段,我认为问题与test3test4的失败有关。

void Main()
{
   List<Currency> values = new List<Currency>() { new Euro(), new Dollar() };

   Dollar d = new Dollar();
   Euro e = new Euro();

   var test1a = (Dollar)e; // valid
   var test1b = (Euro)d; // valid

   Console.WriteLine(values[0].GetType()); // Euro

   var test2 = values[0] as Dollar; // valid

   var test3 = (Dollar)values[0]; // Why does this fail? - InvalidCastException: Unable to cast object of type 'Euro' to type 'Dollar'

   var test4 = values.Cast<Euro>(); // no error
   Console.WriteLine(test4.ToString()); // what's this CastIterator?

   var test5 = test4.ToList(); // Why does this fail? - InvalidCastException: Unable to cast object of type 'Dollar' to type 'Euro'

}

class Currency { public double Amount {get; set;} = 0; }
class Euro : Currency 
{ 
 public Euro(double amount = 0) { this.Amount = amount; }
 public static implicit operator Euro(Dollar d)
 {
    Euro e = new Euro(); e.Amount = d.Amount*1.2; return e;
 }
}

class Dollar : Currency 
{
 public Dollar(double amount = 0) { this.Amount = amount; }
 public static implicit operator Dollar(Euro e)
 {
    Dollar d = new Dollar(); d.Amount = e.Amount/1.2; return d;
 }
}

如您所见,我已经为类指定了隐式转换运算符,但是,这不足以使test3和4正常工作。 这是为什么?

1 个答案:

答案 0 :(得分:0)

如果您想知道LINQ函数的作用,请随时访问reference source in Enumerable.CS

在这里您会找到:

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);
}

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) 
{
    foreach (object obj in source)
    {
        yield return (TResult)obj;
    }
}

那么,对于源序列中的每个对象,它将执行:

(TResult) obj;

要找出出现问题的原因,只需创建您的来源列表,然后开始列举自己:

List<Currency> currencies = ...
foreach (Currency currency in currencies)
{
    Dollar d = (Dollar)currency;
    Euro e = (Euro) currency;
    Console.WriteLine("Dollar {0}; Euro {1}", d, e);
}

您的调试器会告诉您哪里出了问题。

var test2 = values[0] as Dollar; // valid
var test3 = (Dollar)values[0];   // InvalidCastException

test3是否意味着:( (Dollar)values ) [0];。如果加上括号,是否可以解决问题?

 var test3 = (Dollar) (values[0]);