编译器优化匿名类型

时间:2010-07-23 01:04:42

标签: c# .net-4.0 anonymous-types compiler-optimization

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

我一直认为编译器会检查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 个答案:

答案 0 :(得分:2)

你试过吗

bigData2.Except(bigData1.AsQueryable());

我刚刚运行了一个包含40个属性和20,000,000行的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 ;}
}

答案 1 :(得分:2)

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

答案 2 :(得分:1)

匿名类型与任何类型一样,作用于其包含程序集。如果两个适配器在同一个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 );
        }
    }
}