У меня есть новости для вас.
На самом деле возможно... НО! (Да, есть но).
Я предполагаю, что вы используете динамическую библиотеку Linq. Затем вы должны использовать ключевое слово «it», чтобы иметь возможность указать текущий объект, к которому вы хотите применить операцию индексирования.
Однако... Возвращаемый тип данных вашего индексатора - объект, поэтому вы не сможете написать [0] > 100 и [1] = "wpf" из-за несоответствия типов данных.
Кроме того, даже если вы наследуете DynamicObject и добавляете свойства во время выполнения, эти свойства не будут разрешены во время выполнения динамической библиотекой linq в ее текущем состоянии. Вы просто получите, что поле или свойство не существует в типе xxx.
Для этого есть несколько решений, некоторые из которых вы можете принять как решение.
Одно уродливое решение, если у вас есть ограниченное количество типов данных, скажем, n (где n ‹ количество типов в .NET), вы можете использовать n индексаторов с сопоставлением параметров и получить нужный тип данных. Например, если у вас в основном целые числа и некоторые строки:
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, используя что-то вроде (хотя и не говорю, что это хорошая идея):
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