代码之家  ›  专栏  ›  技术社区  ›  Pandincus

匿名类型的编译器优化

  •  7
  • Pandincus  · 技术社区  · 16 年前

    好吧,我知道这是一个黑客,但这是一个小型的数据操作项目,我想玩。;-)

    我一直觉得编译器会检查C程序中使用的所有匿名类型,如果属性相同,它只会在后台创建一个类。

    因此,假设我想从我拥有的一些类型化数据集中创建一个匿名类型:

    var smallData1 = new smallData1().GetData().Select(
        x => new { Name = x.NAME, x.ADDRESS, City = x.CITY, State = x.STATE,
        Zip = x.ZIP, Country = x.COUNTRY, ManagerName = x.MANAGER_NAME,
        ManagerID = x.MANAGER_ID });
    
    var smallData2 = new smallData2().GetData().Select(
        x => new { x.Name, x.ADDRESS, x.City, x.State, x.Zip, x.Country,
        x.ManagerName,x.ManagerID });
    

    我现在可以做一些有趣的事情 smalldata2.except(smalldata1); 等等,一切正常。

    现在,如果我有一对更大的匿名类型呢:

    var bigData1 = new BigAdapter1().GetData().Select(
        x => new { x.FirstName, x.LastName, x.Address, x.City, x.State,
        x.Zip, x.Country, x.Phone, x.Email, x.Website, x.Custom1, x.Custom2,
        x.Custom3, x.Custom4, x.Custom5, x.Custom6, x.Custom7, x.Custom8, x.Custom9,
        x.Custom10, x.Custom11, x.Custom12, x.Custom13, x.Custom14, x.Custom15,
        x.Custom16, x.Custom17, x.Custom18, x.Custom19, x.Custom20, x.Custom21,
        x.Custom22, x.Custom23, x.Custom24, x.Custom25, x.Custom26, x.Custom27,
        x.Custom28, x.Custom29});
    
    var bigData2 = new BigAdapter2().GetData().Select(
        x => new { x.FirstName, x.LastName, x.Address, x.City, x.State, x.Zip,
        x.Country, x.Phone, x.Email, x.Website, x.Custom1, x.Custom2, x.Custom3,
        x.Custom4, x.Custom5, x.Custom6, x.Custom7, x.Custom8, x.Custom9, x.Custom10,
        x.Custom11, x.Custom12, x.Custom13, x.Custom14, x.Custom15, x.Custom16,
        x.Custom17, x.Custom18, x.Custom19, x.Custom20, x.Custom21, x.Custom22,
        x.Custom23, x.Custom24, x.Custom25, x.Custom26, x.Custom27,
        x.Custom28, x.Custom29});
    

    现在当我这样做的时候 bigdata2.except(bigdata1); 编译器抱怨:

    Instance argument: cannot convert from
    'System.Data.EnumerableRowCollection<AnonymousType#1>' to
    'System.Linq.IQueryable<AnonymousType#2>'
    

    为什么?属性太多,所以编译器认为不值得优化?

    谢谢!

    3 回复  |  直到 16 年前
        1
  •  2
  •   Swanny    16 年前

    是的。它不是属性的数量。您如何确定适配器返回的数据类型完全相同?

        2
  •  2
  •   Matt Mitchell    16 年前

    你试过了吗?

    bigData2.Except(bigData1.AsQueryable());
    

    我刚刚运行了一个具有40个属性和20000000行的LINQ示例,没有遇到问题。

    (在linqpad中尝试这个不幸的不可折叠的示例)

    void Main()
    {
     Test t = new Test();
     var a = Enumerable.Range(1,10000000).Select(i => new  
     { 
      t.T0, t.T1, t.T2, t.T3, t.T4, t.T5, t.T6, t.T7, t.T8, t.T9,
      t.T10, t.T11, t.T12, t.T13, t.T14, t.T15, t.T16, t.T17, t.T18, t.T19,
      t.T20, t.T21, t.T22, t.T23, t.T24, t.T25, t.T26, t.T27, t.T28, t.T29,
      t.T30, t.T31, t.T32, t.T33, t.T34, t.T35, t.T36, t.T37, t.T38, t.T39,
     });
    
     Test2 t2 = new Test2();
     var b = Enumerable.Range(1,10000000).Select(i => new  
     { 
      t2.T0, t2.T1, t2.T2, t2.T3, t2.T4, t2.T5, t.T6, t2.T7, t2.T8, t2.T9,
      t2.T10, t2.T11, t2.T12, t2.T13, t2.T14, t2.T15, t2.T16, t2.T17, t2.T18, t2.T19,
      t2.T20, t2.T21, t2.T22, t2.T23, t2.T24, t2.T25, t2.T26, t2.T27, t2.T28, t2.T29,
      t2.T30, t2.T31, t2.T32, t2.T33, t2.T34, t2.T35, t2.T36, t2.T37, t2.T38, t2.T39,
     });
    
     a.Except(b).Dump();
    }
    
    class Test
    {
     public string T0 { get; set ;}
     public string T1 { get; set ;}
     public string T2 { get; set ;}
     public string T3 { get; set ;}
     public string T4 { get; set ;}
     public string T5 { get; set ;}
     public string T6 { get; set ;}
     public string T7 { get; set ;}
     public string T8 { get; set ;}
     public string T9 { get; set ;}
     public string T10 { get; set ;}
     public string T11 { get; set ;}
     public string T12 { get; set ;}
     public string T13 { get; set ;}
     public string T14 { get; set ;}
     public string T15 { get; set ;}
     public string T16 { get; set ;}
     public string T17 { get; set ;}
     public string T18 { get; set ;}
     public string T19 { get; set ;}
     public string T20 { get; set ;}
     public string T21 { get; set ;}
     public string T22 { get; set ;}
     public string T23 { get; set ;}
     public string T24 { get; set ;}
     public string T25 { get; set ;}
     public string T26 { get; set ;}
     public string T27 { get; set ;}
     public string T28 { get; set ;}
     public string T29 { get; set ;}
     public string T30 { get; set ;}
     public string T31 { get; set ;}
     public string T32 { get; set ;}
     public string T33 { get; set ;}
     public string T34 { get; set ;}
     public string T35 { get; set ;}
     public string T36 { get; set ;}
     public string T37 { get; set ;}
     public string T38 { get; set ;}
     public string T39 { get; set ;}
    }
    
    class Test2
    {
     public string T0 { get; set ;}
     public string T1 { get; set ;}
     public string T2 { get; set ;}
     public string T3 { get; set ;}
     public string T4 { get; set ;}
     public string T5 { get; set ;}
     public string T6 { get; set ;}
     public string T7 { get; set ;}
     public string T8 { get; set ;}
     public string T9 { get; set ;}
     public string T10 { get; set ;}
     public string T11 { get; set ;}
     public string T12 { get; set ;}
     public string T13 { get; set ;}
     public string T14 { get; set ;}
     public string T15 { get; set ;}
     public string T16 { get; set ;}
     public string T17 { get; set ;}
     public string T18 { get; set ;}
     public string T19 { get; set ;}
     public string T20 { get; set ;}
     public string T21 { get; set ;}
     public string T22 { get; set ;}
     public string T23 { get; set ;}
     public string T24 { get; set ;}
     public string T25 { get; set ;}
     public string T26 { get; set ;}
     public string T27 { get; set ;}
     public string T28 { get; set ;}
     public string T29 { get; set ;}
     public string T30 { get; set ;}
     public string T31 { get; set ;}
     public string T32 { get; set ;}
     public string T33 { get; set ;}
     public string T34 { get; set ;}
     public string T35 { get; set ;}
     public string T36 { get; set ;}
     public string T37 { get; set ;}
     public string T38 { get; set ;}
     public string T39 { get; set ;}
    }
    
        3
  •  1
  •   Marc Gravell    16 年前

    匿名类型和任何类型一样,都是 范围到其包含程序集 . 只有当两个适配器位于同一个DLL(实际上是模块IIRC)中时,编译器才能将其视为相等的。

    除此之外,我还要检查一下类型…

    static Type Identify<T>(IEnumerable<T>) {return typeof(T);}
    ...
    var t1= Identify(bigData1), t2= Identify(bigData2);
    if(t1 == t2) {
        Console.WriteLine("they're the same");
    } else {
        var props1 = t1.GetProperties(), props2 = t2.GetProperties();
        if(props1.Length != props2.Length) {
            Console.WriteLine(props1.Length + " vs " + props2.Length);
        } else {
            Array.Sort(props1, p => p.Name);
            Array.Sort(props2, p => p.Name);
            for(int i = 0 ; i < props1.Length ; i++) {
                if(props1[i].Name != props2[i].Name)
                    Console.WriteLine(props1[i].Name + " vs " + props2[i].Name);
                if(props1[i].PropertyType != props2[i].PropertyType)
                    Console.WriteLine(props1[i].PropertyType + " vs " + props2[i].PropertyType );
            }
        }
    }