Имам някои новини за вас.
Всъщност е възможно... НО! (Да, има едно но).
Предполагам, че използвате динамичната библиотека Linq. След това трябва да използвате ключовата дума "it", за да можете да посочите текущия обект, към който искате да приложите вашата операция за индексиране.
Въпреки това... Върнатият тип данни на вашия индексатор е обект, така че няма да можете да напишете [0] > 100 и [1] = "wpf" поради несъответствие на типа данни.
Също така, дори ако извлечете от DynamicObject и бихте добавили свойствата по време на изпълнение, тези свойства няма да бъдат разрешени по време на изпълнение от динамичната linq библиотека в нейното текущо състояние. Просто ще получите поле или свойство не съществува в тип xxx.
Има няколко решения за това, някои от които може да приемете като решение.
Едно грозно решение, ако имате ограничен брой типове данни, да речем n (където n ‹ броят типове в .NET), можете да използвате n индексатори със съвпадение на параметри и да получите типа данни, който искате. Например, ако имате предимно int и някои низове:
it[0] > 100 AND it[1, "dummy"] = "wpf" //The dummy parameter allows you to specify return type.
Друго грозно решение, Dynamic Linq има поддръжка за използване на методите ToString() и Convert, така че можете например да напишете същата заявка като по-горе:
Convert.ToDouble(it[0]) > 100 AND it[1].ToString() = "wpf".
Трето грозно решение, можете да използвате конвенция, при която обвивате изрази по начин, който ви казва как да преобразувате данните. Например можете да напишете:
it[0] > 100 AND it{1} = "wpf"
И заменете "it[" с "Convert.ToDouble(it[" и така нататък...
Ако греша, мисля, че не можете да използвате и общ индексатор с библиотеката. И Convert.ChangeType не ви помага в този случай, тъй като върнатият тип все още е обект.
Може би аз или някой друг ще пренапише библиотеката известно време, за да поддържа подобни неща, но нямам време да го направя в близко бъдеще (няколко седмици).
Е, съжалявам, но трябва да съм някъде след 15 минути, така че ще трябва да вземем по-хубавите решения по-късно, надявам се!
телепортирам се на срещата
АКТУАЛИЗАЦИЯ:
Мисля, че може би съм намерил решение на вашия (и моя) проблем!
В библиотеката DLINQ можете да добавите член в интерфейса(ите) на IxxxSignatures за типа, с който искате да можете да работите.
И така, добавих (например) в IEqualitySignatures:
void F(Object x, Int32 y);
И модифицира (в този случай) метода ParseComparison в блока else по този начин.
left = Expression.Convert(left, right.Type);
И, вярвате или не, проработи :)
Не съм тествал всички видове операции, тъй като не съм добавил подписите за другите типове и операции, но трябва да е съвсем лесно да се направи!
АКТУАЛИЗАЦИЯ
Актуализира някои незначителни неща по-горе..
Експериментирам още малко по този въпрос и въпреки че може да не е най-красивото решение, можете да направите нещо подобно (DataObject е просто DynamicObject с индексатор):
[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);
}
И някакъв метод за форматиране като (преструвам се, че съм написал пълен метод):
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);
}
Разбира се, вместо това можем да имаме метод за разширение.
Или... Можем да поставим метода в DLINQ lib, като използваме нещо като (все пак не казвам, че е добра идея):
if (typeof(T).GetInterface("IDynamicMetaObjectProvider", true) != null)
whereClause = whereClause.FormatQuery();
И проверете дали типът внедрява индексатор на низове, разбира се, нещо като (игнорирайки атрибута IndexerName тук):
if (t.GetType().GetProperty("Item") != null)
което би позволило на "нормалните потребители" да пишат:
data.Where("dblProp > 9.0 AND intProp = 8 AND strProp = 'Hello'")
Е, може би не е добре да има тези неща там, но схващате смисъла. Можеше да имаш! :)
person
Johan
schedule
28.01.2012