2010-07-23 4 views
7

OK OK, je sais que c'est un hack, mais c'était pour un petit projet de manipulation de données et je voulais jouer. ;-)Optimisations du compilateur de types anonymes

J'ai toujours eu l'impression que le compilateur examinerait tous les types anonymes utilisés dans un programme C# et que si les propriétés étaient les mêmes, cela créerait seulement une classe en arrière-plan.

Alors disons que je veux créer un type anonyme de certains jeux de données typées que j'ai:

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

Je peux maintenant faire des choses amusantes comme smallData2.Except (smallData1); etc., et tout fonctionne.

Maintenant, si j'ai une plus grande paire de types anonymes:

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

Maintenant, quand je fais bigData2.Except (bigData1); le compilateur se plaint:

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

Pourquoi? Trop de propriétés, donc le compilateur décide que ça ne vaut pas la peine d'optimiser?

Merci!

Répondre

2

Yep. Ce n'est pas le nombre de propriétés. Êtes-vous sûr que vos adaptateurs retournent exactement les mêmes types de données?

+0

Oui, les adaptateurs retournent des types de données légèrement différents, mais la différence est uniquement le type de jeu de données typé (ils proviennent de bases de données différentes). Toutes les propriétés sont des chaînes, c'est pourquoi j'ai pensé que j'utiliserais simplement un type anonyme et que cela me permettrait de traiter les données comme un type de type au lieu de deux. – Pandincus

+0

OMG O D EST CE DOUBLE? Euh ... d'accord, vous aviez tout à fait raison. L'un des types est en effet différent. Je suppose que c'est ce qui arrive quand vous codez tard dans la nuit: -O – Pandincus

2

Avez-vous essayé

bigData2.Except(bigData1.AsQueryable()); 

J'ai couru juste un exemple LINQ avec 40 propriétés et 20.000.000 lignes et je ne lance pas dans un problème.

(Essayez ceci malheureusement pas exemple pliable dans 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 ;} 
} 
+0

Je suppose que le problème est que AnonymousType # 1 ne peut pas être jeté à AnonymousType # 2 ... la question est, pourquoi sont-ils deux différents types pour commencer? –

1

Les types anonymes, comme tout type, sont portée à leur ensemble contenant. Le compilateur ne peut traiter comme égales que si les deux adaptateurs sont dans la même DLL (en fait, le module IIRC).

Au-delà de cela, je voudrais vérifier les types ...

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