代码之家  ›  专栏  ›  技术社区  ›  Ryan Versaw

当定义了隐式强制转换时,为什么LINQ强制转换<t>操作失败?

  •  16
  • Ryan Versaw  · 技术社区  · 15 年前

    我创建了两个类,其中一个类在它们之间具有隐式强制转换:

    public class Class1
    {
        public int Test1;
    }
    
    public class Class2
    {
        public int Test2;
    
        public static implicit operator Class1(Class2 item)
        {
            return new Class1{Test1 = item.Test2};
        }
    }
    

    当我创建一个类型的新列表并尝试将<t>强制转换为另一个类型时,该列表将失败,并出现invalidCastException:

    List<Class2> items = new List<Class2>{new Class2{Test2 = 9}};
    foreach (Class1 item in items.Cast<Class1>())
    {
        Console.WriteLine(item.Test1);
    }
    

    不过,这样做很好:

    foreach (Class1 item in items)
    {
        Console.WriteLine(item.Test1);
    }
    

    为什么在使用cast时不调用隐式强制转换?

    4 回复  |  直到 11 年前
        1
  •  5
  •   Ruben Bartelink    15 年前

    因为,通过Reflector查看代码时,Cast不会尝试将任何隐式的Cast运算符(Linq Cast代码针对各种特殊情况进行了大量优化,但没有考虑到这一方向)考虑在内(因为许多.NET语言不会这样做)。

    在没有考虑到思考和其他事情的情况下,泛型没有提供任何现成的方法来在任何情况下考虑这些额外的东西。

    编辑:一般来说,更复杂的设施,如隐式/显式、相等运算符等,一般不由像LINQ这样的通用设施处理。

        2
  •  2
  •   Maslow    14 年前

    如果需要,还可以使用此功能进行转换的铸造:

    public static IEnumerable<TDest> CastAll<TItem, TDest>(this IEnumerable<TItem> items)
    {
     var p = Expression.Parameter(typeof(TItem), "i");
     var c = Expression.Convert(p, typeof(TDest));
     var ex = Expression.Lambda<Func<TItem, TDest>>(c, p).Compile();
    
     foreach (var item in items)
     {
        yield return ex(item);
     }
    }
    

    http://adventuresdotnet.blogspot.com/2010/06/better-more-type-safe-alternative-to.html

        3
  •  1
  •   David McEwing    15 年前

    foreach (Class1 item in items.ConvertAll<Class1>((i) => (Class1)i))
    {
         Console.WriteLine(item.Test1);
    }
    

    foreach (Class1 item in items.ConvertAll<Class1>(i => i))
    {
         Console.WriteLine(item.Test1);
    }
    
        4
  •  0
  •   WhiteN01se    14 年前

    List items = new List{new Class2{Test2 = 9}};
    foreach (Class1 item in (from x in items select (Class1)x))
    {
        Console.WriteLine(item.Test1);
    }