In primo luogo ho visto IEqualityComparer for anonymous type e le risposte non ci non rispondere alla mia domanda, per l'ovvia ragione che ho bisogno di un IEqualityComparer
non e IComparer
per l'uso con il metodo di Linq Distinct()
. Ho controllato le altre risposte troppo e questi a corto di una soluzione ...IEqualityComparer per tipo Annoymous
Il problema
ho qualche codice per manipolare e tirare record in da un DataTable
var glext = m_dtGLExt.AsEnumerable();
var cflist =
(from c in glext
orderby c.Field<string>(m_strpcCCType),
c.Field<string>(m_strpcCC),
c.Field<string>(m_strpcCCDesc),
c.Field<string>(m_strpcCostItem)
select new
{
CCType = c.Field<string>(m_strpcCCType),
CC = c.Field<string>(m_strpcCC),
CCDesc = c.Field<string>(m_strpcCCDesc),
CostItem = c.Field<string>(m_strpcCostItem)
}).Distinct();
ma Ho bisogno che il metodo distinto sia insensibile al maiuscolo/minuscolo. Quello che mi sta buttando qui è l'uso di tipi anonimi.
tentata soluzione 1
Se avessi SomeClass
che aveva oggetti concreti ho potuto ovviamente fare
public class SumObject
{
public string CCType { get; set; }
public string CC { get; set; }
public string CCDesc { get; set; }
public string CostItem { get; set; }
}
ho potuto ovviamente fare questo
List<SumObject> lso = new List<SumObject>()
{
new SumObject() { CCType = "1-OCC", CC = "300401", CCDesc = "Rooney", CostItem = "I477" },
new SumObject() { CCType = "1-OCC", CC = "300401", CCDesc = "Zidane", CostItem = "I677" },
new SumObject() { CCType = "1-OCC", CC = "300401", CCDesc = "Falcao", CostItem = "I470" },
};
var e = lso.Distinct(new SumObjectComparer()); // Great :]
dove
class SumObjectComparer : IEqualityComparer<SumObject>
{
public bool Equals(SumObject x, SumObject y)
{
if (Object.ReferenceEquals(x, y))
return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.CCType.CompareNoCase(y.CCType) == 0 &&
x.CC.CompareNoCase(y.CC) == 0 &&
x.CCDesc.CompareNoCase(y.CCDesc) == 0 &&
x.CostItem.CompareNoCase(y.CostItem) == 0;
}
public int GetHashCode(SumObject o)
{
if (Object.ReferenceEquals(o, null))
return 0;
int hashCCType = String.IsNullOrEmpty(o.CCType) ?
0 : o.CCType.ToLower().GetHashCode();
int hashCC = String.IsNullOrEmpty(o.CC) ?
0 : o.CC.ToLower().GetHashCode();
int hashCCDesc = String.IsNullOrEmpty(o.CCDesc) ?
0 : o.CCDesc.ToLower().GetHashCode();
int hashCostItem = String.IsNullOrEmpty(o.CostItem) ?
0 : o.CostItem.ToLower().GetHashCode();
return hashCCType^hashCC^hashCCDesc^hashCostItem;
}
}
Tuttavia, l'utilizzo di tipi anonimi nella query Linq sopra mi sta lanciando.
Tentativo Soluzione 2
Per tentare un'altra soluzione a questo (e perché ho lo stesso problema altrove) ho generato la seguente classe di confronto generico
public class GenericEqualityComparer<T> : IEqualityComparer<T>
{
Func<T, T, bool> compareFunction;
Func<T, int> hashFunction;
public GenericEqualityComparer(Func<T, T, bool> compareFunction, Func<T, int> hashFunction)
{
this.compareFunction = compareFunction;
this.hashFunction = hashFunction;
}
public bool Equals(T x, T y) { return compareFunction(x, y); }
public int GetHashCode(T obj) { return hashFunction(obj); }
}
modo che io possa tentare di fare
var comparer = new GenericEqualityComparer<dynamic>(
(x, y) => { /* My equality stuff */ },
o => { /* My hash stuff */ });
ma questo getta il valore restituito come IEnumerable<dynamic>
che a sua volta effettua il mio prossimo utilizzo di cflist
, in modo che in una seguente query lo join
non riesca.
var cf =
(from o in cflist
join od in glext
on new { o.CCType, o.CC, o.CCDesc, o.CostItem } equals new
{
CCType = od.Field<string>(m_strpcCCType),
CC = od.Field<string>(m_strpcCC),
CCDesc = od.Field<string>(m_strpcCCDesc),
CostItem = od.Field<string>(m_strpcCostItem)
}
into c
select new { ... }
Non voglio entrare in brutto fusione da e per IEnumerable<T>
s a causa del pesante uso di questo codice ...
Domanda
C'è un modo posso crea il mio IEquailityComparer
per i miei tipi anonimi?
Grazie per il vostro tempo.
La prima soluzione avrebbe funzionato se si fosse sostituito l'oggetto anonimo 'select new' con un' select new SumObject' object. Qual è il problema con l'utilizzo di un oggetto anonimo, se hai già creato una classe con nome per questo? – dasblinkenlight
Non ho e non posso, questo è il punto. Se potessi, sarebbe facile. Ho anche molti altri posti in cui queste distinte operazioni funzionano con le query selezionate di linq e i tipi anonimi, quindi mi piacerebbe una soluzione più generale ... – MoonKnight
Sarà lento, ma suppongo che dovrai usare il reflection per scrivere un IEqualityComparer