используя выражение <Func <object>> в качестве ключа в словаре - PullRequest
3 голосов
/ 13 декабря 2010

Как я могу использовать тип выражения> в качестве ключа в словаре?

Я только начал играть с экземплярами Expression и не уверен, возможно ли то, что я хочу сделать.

Кажется, что 2 одинаковых выражения не равны, так как при попытке я могу поместить запись в словарь, используя выражение в качестве ключа, но он возвращает ложь, когда я спрашиваю словарь, содержит ли он ключ, если только я не используютот же экземпляр выражения.

TypeToTest test = new TypeToTest();
Expression<Func<object>> expression = ()=>test.PropertyA;
IDictionary<Expression<Func<object>>,bool> dictionary = new Dictionary<Expression<Func<object>>, bool> ();
dictionary[expression] = true;
Assert.That (dictionary.ContainsKey(expression), Is.True);
Assert.That (dictionary.ContainsKey(()=>test.PropertyA), Is.True);

последняя строка выше терпит неудачу, когда я хотел бы, чтобы она была успешной.

Цель состоит в том, чтобы иметь возможность определять набор правил, которые применяются к свойствамили методы объекта, чтобы я мог определить, например, является ли свойство доступным для редактирования или можно ли удалить значение с определенным ключом в словаре.Я не хочу иметь флаг на объекте, который определяет, является ли он редактируемым (так как редактируемость может отличаться для разных свойств), и другой, который определяет, можно ли его удалить, а скорее другой класс, который будет отвечать за поддержание связанных правилс объектом, так что по мере расширения объекта в будущем могут быть добавлены дополнительные правила для описания редактируемости / доступности / возможности удаления / составных частей объекта.если это имеет смысл.

Здесь был похожий пост здесь , но это похоже на ключ, основанный на имени свойства, где, как, я хотел бы, чтобы можно было также ввести ключ на метод и аргументы, поэтому яможет помочь определить редактируемость объектов, хранящихся в словаре, на основе ключа.

Возможно ли что-то подобное, или это пирог в небе?

Ответы [ 2 ]

4 голосов
/ 13 декабря 2010

Это ожидаемое поведение при сравнении различных ссылок, когда этот тип не переопределяет Equals или не реализует IEquatable<T>.Вы могли бы написать собственный компаратор (возможно, просто сравнив ToString()) и передать его в словарь - но IMO Expression не является хорошим выбором ключа. не обязательно устойчивое использование через ToString () ;использовать по своему усмотрению:

class Program {
    static void Main() {
        TypeToTest test = new TypeToTest();
        Expression<Func<object>> expression = () => test.PropertyA;
        IDictionary<Expression<Func<object>>, bool> dictionary =
            new Dictionary<Expression<Func<object>>, bool>(
               new ToStringComparer<Expression<Func<object>>>());
        dictionary[expression] = true;

        bool x = dictionary.ContainsKey(expression), // true
            y = dictionary.ContainsKey(() => test.PropertyA); // true
    }
}
class ToStringComparer<T> : IEqualityComparer<T> where T : class {
    public bool Equals(T x, T y) {
        if ((x == null && y == null) || ReferenceEquals(x,y)) return true;
        if (x == null || y == null) return false;
        return x.ToString() == y.ToString();
    }
    public int GetHashCode(T obj) {
        return obj == null ? 0 : obj.ToString().GetHashCode();
    }
}
2 голосов
/ 13 декабря 2010

Подклассы типа Expression не переопределяют методы Equals и GetHashCode, что затрудняет их использование в качестве ключей словаря.В вашем словаре используется равенство ссылок, и два вхождения ()=>test.PropertyA создают два различных объекта дерева выражений.

Вы можете написать собственную реализацию IEqualityComparer<Expression> и передать ее в конструктор словаря.В вашем компараторе вы бы написали Equals и GetHashCode методы, которые обрабатывали каждый из Expression классов и сравнивали их свойства.

...