Zum einen habe ich gesehen, IEqualityComparer for anonymous type und die Antworten dort nicht beantwortet meine Frage, aus dem offensichtlichen Grund, die ich brauche eine IEqualityComparer
nicht und IComparer
für die Verwendung mit Distinct()
Methode des Linq. Ich habe die anderen Antworten zu überprüfen und diese ermangeln einer Lösung ...IEqualityComparer für Annoymous Typ
Das Problem
ich einige Code haben zu manipulieren und ziehen Datensätze in einer 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();
aber Ich brauche die eindeutige Methode, um zwischen Groß- und Kleinschreibung zu unterscheiden. Was mich hierher wirft, ist die Verwendung anonymer Typen.
Versuchte Lösung 1
Wenn ich SomeClass
hatte, die ich konkrete Gegenstände hatte offensichtlich
public class SumObject
{
public string CCType { get; set; }
public string CC { get; set; }
public string CCDesc { get; set; }
public string CostItem { get; set; }
}
Ich könnte natürlich tun dies
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 :]
wo
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;
}
}
Allerdings wirft mich die Verwendung von anonymen Typen in der obigen Linq-Abfrage.
Versuchte Lösung 2
Um eine andere Lösung dieses Problems zu versuchen (und weil ich habe das gleiche Problem an anderer Stelle) I erzeugt die folgende allgemeine comparer Klasse
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); }
}
, so dass ich versuchen könnte zu tun
var comparer = new GenericEqualityComparer<dynamic>(
(x, y) => { /* My equality stuff */ },
o => { /* My hash stuff */ });
aber dies wirft den zurückgegebenen Wert als IEnumerable<dynamic>
was wiederum Auswirkungen meiner bevorstehenden Verwendung von cflist
, so dass in einer folgenden Abfrage die join
schlägt fehl.
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 { ... }
Ich will nicht wegen der schweren Verwendung dieses Codes zu und von IEnumerable<T>
s in hässliches Gießen erhalten ...
Frage
Gibt es eine Möglichkeit kann ich Erstelle mein ein IEquailityComparer
für meine anonymen Typen?
Danke für Ihre Zeit.
Ihre erste Lösung hätte funktioniert, wenn Sie Ihr anonymer 'Select new' -Objekt durch ein 'Select new SumObject'-Objekt ersetzt haben. Was ist mit der Verwendung eines anonymen Objekts wichtig, wenn Sie bereits eine benannte Klasse dafür erstellt haben? – dasblinkenlight
Ich habe nicht und kann nicht, das ist der Punkt. Wenn ich könnte, wäre es einfach. Ich habe auch mehrere andere Orte, wo diese unterschiedliche Operation mit linq Select-Abfragen und anonyme Typen arbeiten, so würde ich eine allgemeinere Lösung wünschen ... – MoonKnight
Es wird langsam sein, aber ich denke, Sie müssen Reflektion verwenden, um eine IEqualityComparer