Ich versuche, eine dynamische LINQ-Abfrage zu verwenden, um ein IEnumerable <T> aus einer Objektauflistung (Linq zu Object) abzurufen, jedes der Objekte in der Sammlung haben eine interne Sammlung mit einem anderen Satz von Objekten, wo die Daten gespeichert sind, diese Werte werden über einen Indexer aus der äußeren Sammlung aufgerufen
Die dynamische Linq-Abfrage gibt die gefilterte Menge erwartungsgemäß zurück, wenn Sie mit stark typisierten Objekten arbeiten, aber mein Objekt speichert die Daten in einem Mitglied des Typs dynamic . Siehe das folgende Beispiel:
public class Data
{
public Data(string name, dynamic value)
{
this.Name = name;
this.Value = value;
}
public string Name { get; set; }
public dynamic Value { get; set; }
}
public class DataItem : IEnumerable
{
private List<Data> _collection;
public DataItem()
{ _collection = new List<Data>(); }
public dynamic this[string name]
{
get
{
Data d;
if ((d = _collection.FirstOrDefault(i => i.Name == name)) == null)
return (null);
return (d.Value);
}
}
public void Add(Data data)
{ _collection.Add(data); }
public IEnumerator GetEnumerator()
{
return _collection.GetEnumerator();
}
}
public class Program
{
public void Example()
{
List<DataItem> repository = new List<DataItem>(){
new DataItem() {
new Data("Name", "Mike"),
new Data("Age", 25),
new Data("BirthDate", new DateTime(1987, 1, 5))
},
new DataItem() {
new Data("Name", "Steve"),
new Data("Age", 30),
new Data("BirthDate", new DateTime(1982, 1, 10))
}
};
IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it[\"Age\"] == 30");
if (result.Count() == 1)
Console.WriteLine(result.Single()["Name"]);
}
Wenn ich das obige Beispiel ausführe, bekomme ich: Operator '==' inkompatibel mit den Operandentypen 'Object' und 'Int32'
Sind dynamische Elemente inkompatibel mit Dynamic Linq-Abfragen? Oder gibt es eine andere Möglichkeit zum Konstruieren von Ausdrücken, die beim Umgang mit Elementen vom Typ dynamic korrekt ausgewertet werden?
Vielen dank für Deine Hilfe.
Sind dynamische Elemente inkompatibel mit Dynamic Linq-Abfragen? Oder gibt es eine andere Möglichkeit zum Konstruieren von Ausdrücken, die beim Umgang mit Membern des Typs dynamic richtig ausgewertet werden?
Beide können zusammenarbeiten. Machen Sie einfach eine Konvertierung zu Int32, bevor Sie den Vergleich durchführen:
IEnumerable<DataItem> result =
repository.AsQueryable<DataItem>().Where("Int32(it[\"Age\"]) == 30");
Edit 1: Allerdings ist die Verwendung der dynamischen Bindung in Verbindung mit Linq generell eingeschränkt, da dynamische Operationen in Ausdrucksbäumen nicht erlaubt sind. Betrachten Sie die folgende Linq-To-Objects-Abfrage:
IEnumerable<DataItem> result = repository.AsQueryable().
Where(d => d["Age"] == 30);
Dieses Code-Snippet wird aus dem oben genannten Grund nicht kompiliert.
Edit 2: In Ihrem Fall (und in Verbindung mit Dynamic Linq) gibt es einige Möglichkeiten, sich mit den in Edit 1 und in der Originalfrage erwähnten Problemen zu hacken. Beispielsweise:
// Variant 1: Using strings all the way
public void DynamicQueryExample(string property, dynamic val)
{
List<DataItem> repository = new List<DataItem>(){
new DataItem() {
new Data("Name", "Mike"),
new Data("Age", 25),
new Data("BirthDate", new DateTime(1987, 1, 5))
},
new DataItem() {
new Data("Name", "Steve"),
new Data("Age", 30),
new Data("BirthDate", new DateTime(1982, 1, 10))
}
};
// Use string comparison all the time
string predicate = "it[\"{0}\"].ToString() == \"{1}\"";
predicate = String.Format(whereClause , property, val.ToString());
var result = repository.AsQueryable<DataItem>().Where(predicate);
if (result.Count() == 1)
Console.WriteLine(result.Single()["Name"]);
}
Program p = new Program();
p.DynamicQueryExample("Age", 30); // Prints "Steve"
p.DynamicQueryExample("BirthDate", new DateTime(1982, 1, 10)); // Prints "Steve"
p.DynamicQueryExample("Name", "Mike"); // Prints "Steve" (nah, just joking...)
oder:
// Variant 2: Detecting the type at runtime.
public void DynamicQueryExample(string property, string val)
{
List<DataItem> repository = new List<DataItem>(){
new DataItem() {
new Data("Name", "Mike"),
new Data("Age", 25),
new Data("BirthDate", new DateTime(1987, 1, 5))
},
new DataItem() {
new Data("Name", "Steve"),
new Data("Age", 30),
new Data("BirthDate", new DateTime(1982, 1, 10))
}
};
string whereClause = "{0}(it[\"{1}\"]) == {2}";
// Discover the type at runtime (and convert accordingly)
Type type = repository.First()[property].GetType();
string stype = type.ToString();
stype = stype.Substring(stype.LastIndexOf('.') + 1);
if (type.Equals(typeof(string))) {
// Need to surround formatting directive with ""
whereClause = whereClause.Replace("{2}", "\"{2}\"");
}
string predicate = String.Format(whereClause, stype, property, val);
var result = repository.AsQueryable<DataItem>().Where(predicate);
if (result.Count() == 1)
Console.WriteLine(result.Single()["Name"]);
}
var p = new Program();
p.DynamicQueryExample("Age", "30");
p.DynamicQueryExample("BirthDate", "DateTime(1982, 1, 10)");
p.DynamicQueryExample("Name", "Mike");
Ist der folgende Code hilfreich für Sie?
IEnumerable<DataItem> result = repository.AsQueryable<DataItem>().Where("it[\"Age\"].ToString() == \"30\"");
Damit dies jedoch funktioniert, müssen alle Ihre Typen, die dem Value
Member Ihrer Data
Klasse zugewiesen werden können, über eine sinnvolle Implementierung der ToString
Methode ToString
.