J'ai quelques nouvelles pour vous.
C'est en fait possible ... MAIS! (Oui, il y a un mais) Je suppose que vous utilisez la bibliothèque Linq dynamique. Vous devez ensuite utiliser le mot-clé "it" pour pouvoir spécifier l'objet courant auquel vous souhaitez appliquer votre opération d'indexation. Cependant, le type de données de retour de votre indexeur est objet, vous ne pourrez donc pas écrire [0]> 100 et [1] = "wpf" en raison d'une discordance de type de données. De plus, même si vous dérivez de DynamicObject et ajoutez les propriétés à l'exécution, ces propriétés ne seront pas résolues à l'exécution par la bibliothèque linq dynamique dans son état actuel. Vous obtiendriez juste un champ ou une propriété n'existe pas dans le type xxx.
Il existe plusieurs solutions à ce problème, dont certaines peuvent être considérées comme une solution.
Une solution laide, si vous avez un nombre limité de types de données, par exemple n (où n < le nombre de types .NET), vous pouvez utiliser n indexeurs avec mise en correspondance des paramètres et obtenir le type de données que vous vouloir. Pour exemple, si vous avez la plupart ints et quelques cordes:
it[0] > 100 AND it[1, "dummy"] = "wpf" //The dummy parameter allows you to specify return type.
Une autre solution laid, dynamique Linq a un support pour l'utilisation du ToString() et Convert-méthodes, donc, vous pouvez par exemple écrire le même requête comme ci-dessus:
Convert.ToDouble(it[0]) > 100 AND it[1].ToString() = "wpf".
une troisième solution laide, vous pouvez utiliser une convention où vous enveloppez déclarations d'une manière qui vous indique comment convertir les données. Pour exemple, vous pouvez écrire:
it[0] > 100 AND it{1} = "wpf"
et remplacer "il [" avec "Convert.ToDouble (il [" et ainsi de suite ...
Si je suis bon, je pense que vous ne pouvez pas non plus utiliser un indexeur générique avec la bibliothèque, et Convert.ChangeType ne vous convient pas dans ce cas puisque le type de retour est toujours object.Peut-être que moi ou quelqu'un d'autre réécrira la bibliothèque un certain temps pour supporter ce genre de choses, mais je n'ai pas le temps de le faire dans un proche avenir (quelques semaines).
Eh bien, je suis désolé, mais je dois être quelque part dans 15 min, donc nous devrons prendre les meilleures solutions plus tard j'espère!
me téléporter à la réunion
MISE À JOUR:
Je pense que je l'ai trouvé une solution à votre problème (et mon)!
Dans la bibliothèque DLINQ, vous pouvez ajouter un membre dans l'interface (s) IxxxSignatures pour le type avec lequel vous souhaitez pouvoir travailler.
Alors, j'ai ajouté (par exemple) dans les IEqualitySignatures:
void F(Object x, Int32 y);
Modifiés le (dans ce cas) ParseComparison méthode dans le bloc autre comme celui-ci.
left = Expression.Convert(left, right.Type);
Et, croyez-le ou non, cela a fonctionné :)
Je ne l'ai pas testé toutes sortes d'opérations, puisque je ne l'ai pas ajouté les signatures pour les autres types et opérations, mais il devrait être tout à fait simple à faire!
MISE À JOUR
mis à jour certaines choses mineures ci-dessus ..
je suis expérimenter un peu plus sur ce sujet et alors qu'il pourrait ne pas être la plus jolie solution soit, vous pourriez faire quelque chose comme ça (DataObject est juste un DynamicObject avec un indexeur):
[TestMethod]
public void DynamicTest()
{
List<DataObject> dataObjects = new List<DataObject>();
dynamic firstObject = new DataObject();
dynamic secondObject = new DataObject();
firstObject.dblProp = 10.0;
firstObject.intProp = 8;
firstObject.strProp = "Hello";
secondObject.dblProp = 8.0;
secondObject.intProp = 8;
secondObject.strProp = "World";
dataObjects.Add(firstObject);
dataObjects.Add(secondObject);
/* Notice the different types */
string newQuery = FormatQuery("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'");
var result = dataObjects.Where(newQuery);
Assert.AreEqual(result.Count(), 1);
Assert.AreEqual(result.First(), firstObject);
}
Et une sorte de méthode de format comme (faites semblant écrit une méthode Ive complète): 01
public string FormatQuery(string query)
{
query = query.Replace('\'', '\"');
string[] operators = new string[] { "<", ">", "!=", "<=", ">=", "<>", "=" };
string[] parts = query.Split();
for (int i = 0; i < parts.Length; i++)
{
if (operators.Contains(parts[i]))
{
parts[i - 1] = "it[\"" + parts[i - 1] + "\"]";
}
}
return String.Join(" ", parts);
}
Nous pourrions bien sûr avoir une méthode d'extension à la place.
Ou ... On pourrait mettre la méthode dans le DLINQ lib en utilisant quelque chose comme (pas dire une bonne idée cependant):
if (typeof(T).GetInterface("IDynamicMetaObjectProvider", true) != null)
whereClause = whereClause.FormatQuery();
Et, vérifiez si le type implémente une chaîne indexeur bien sûr , quelque chose comme (en ignorant IndexerName attribut ici):
if (t.GetType().GetProperty("Item") != null)
qui permettrait à un utilisateur "normal" d'écrire:
data.Where("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'")
Eh bien, ce n'est peut-être pas bon d'avoir ce genre de choses, mais vous avez compris. Tu aurais pu! :)
vraiment? Je ne pense pas que vous ayez besoin de faire des choses aussi laides, voyez ma réponse. – Krizz
Oui, je sais. J'essayais juste de faire le point que le type est objet et donc certaines opérations ne s'appliquent pas sans conversion. Ce serait bien d'avoir une conversion implicite. Peut-être que DLINQ pourrait regarder la valeur du côté droit et convertir le côté gauche (je sais, il fait déjà une partie de cela, mais les libs pourraient toujours faire plus pour vous: P). – Johan
Merci pour cette excellente réponse. Je comprends maintenant le contexte et ce qui est possible. Mais je ne suis pas vraiment satisfait :( J'ai essayé ce jour à – Schorsch