У меня есть для вас новости.
Это действительно возможно ... НО! (Да, но есть).
Я предполагаю, что вы используете динамическую библиотеку Linq. Затем вы должны использовать ключевое слово «it», чтобы иметь возможность указать текущий объект, к которому вы хотите применить операцию индексирования.
Однако ... Тип возвращаемого значения вашего индексатора - объект, поэтому вы не сможете записать [0]> 100 и [1] = "wpf" из-за несоответствия типов данных.
Кроме того, даже если вы наследуете DynamicObject и добавляете свойства во время выполнения, эти свойства не будут разрешены во время выполнения динамической библиотекой linq в ее текущем состоянии. Вы бы просто получили поле или свойство не существует в типе xxx.
Существует несколько решений, некоторые из которых вы можете принять за решение.
Одно уродливое решение, если у вас ограниченное количество типов данных, скажем, n
(где n <количество типов в .NET), вы можете использовать n
индексаторы с сопоставлением параметров и получить нужный тип данных. За
Например, если у вас есть в основном целые числа и несколько строк: </p>
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 минут, так что, надеюсь, мы должны принять более удачные решения позже!
телепортируясь на собрание
UPDATE:
Думаю, я нашел решение вашей (и моей) проблемы!
В библиотеке DLINQ вы можете добавить члена в интерфейс (ы) IxxxSignatures для типа, с которым вы хотели бы работать.
Итак, я добавил (например) в IEqualitySignatures:
void F(Object x, Int32 y);
И изменил (в данном случае) метод ParseComparison в блоке else следующим образом.
left = Expression.Convert(left, right.Type);
И, хотите верьте, хотите нет, это сработало:)
Я не проверял все виды операций, так как я не добавил сигнатуры для других типов и операций, но это должно быть довольно просто сделать!
UPDATE
Обновлены некоторые мелочи выше ..
Я немного поэкспериментирую с этим, и хотя это может быть не самым привлекательным решением, вы можете сделать что-то подобное (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'")
Ну, может быть, нехорошо иметь там такие вещи, но вы понимаете. Вы могли бы иметь! :)