2015-03-16 4 views
1

Ниже выражения сравнивает свойство NAME со значением PETER.MemberExpression, build Expression.Property из класса

  ParameterExpression pe = Expression.Parameter(typeof(T), "x"); 
      MemberExpression member = Expression.Property(pe, "name"); 
      ConstantExpression value = Expression.Constant("Peter"); 
      exp = Expression.Equal(member, value); 

Что делать, если свойство является класс:

  public class Address 
      { 
       public string Name {get; set;} 
      } 

Тогда выражение будет выглядеть нечто похожее на это:

  MemberExpression member = Expression.Property(pe, "Address.Name"); 
      ConstantExpression value = Expression.Constant("Peter"); 
      exp = Expression.Equal(member, value); 

Это не потому, что тип член не соответствует тип значения.

Итак, вопрос: как построить выражение, которое будет работать с использованием вышеприведенного класса?

Я использую это выражение в запросе NHibernate.Linq:

 var q = from f in data //of type IQueryable<T> 
      select f; 
     if (filter != null) //filter of type Expression<Func<T, bool>> 
      q = q.Where(filter); 
     etc.... 

Спасибо.

UPDATE Петром:

на основе коду из Ксанатоса (следующий пост) я создал следующий тест, чтобы понять, как это работает. Это не очень отличается от того, что делают xanatos, но сначала я не мог заставить его работать, поэтому я решил написать его в одном простом тесте, и это было сделано. С благодарностью Ксанатосом:

[Test] 
    public void FilterWithDeepProperties() 
    { 
     //Arrange 
     IGenericGridRepository repository = ObjectFactory.GetInstance<IGenericGridRepository>(); 

     FilterDescriptor filter = new FilterDescriptor("AgreementId.Name", FilterOperator.IsEqualTo, "a name"); 
     string[] properties = filter.Member.Split('.'); 
     ParameterExpression pe = Expression.Parameter(typeof(SampleDomain), "x"); 

     //Act 
     Expression lastMember = pe; 
     for (int i = 0; i < properties.Length; i++) 
     { 
      MemberExpression member = Expression.Property(lastMember, properties[i]); 
      lastMember = member; 
     } 
     ConstantExpression valueExpression = Expression.Constant(filter.Value); 
     Expression equalityExpression = Expression.Equal(lastMember, valueExpression); 
     Expression<Func<SampleDomain, bool>> where = Expression.Lambda<Func<SampleDomain, bool>>(equalityExpression, pe); 
     var result = repository.GetObjects<SampleDomain>(filter: where); 

     //Assert 
     result.Count().Should().BeGreaterThan(0, "because there are many schedule items equals to " + filter.Value); 
    } 
+0

Вы ищете из неправильная точка зрения. 'typeof (T)' уже является типом (например, классом), поэтому в вашем примере 'typeof (T)' is 'typeof (Address)' ... если не существует над-объекта 'Person', который имеет 'Адрес', который имеет 'string Name' ... – xanatos

+0

Я получаю его, но это происходит, когда вы заканчиваете (над-объектом), как и следующий образец: выберите t. *, A.name из SomeTable t inner join AddressTable a на a.Id = t.AddressTableId, где a.name = 'Peter'. –

ответ

1

Вы, вероятно, хотите что-то вроде:

public static Expression<Func<TSource, bool>> GetEquality<TSource>(object value, params string[] properties) 
{ 
    ParameterExpression pe = Expression.Parameter(typeof(TSource), "source"); 

    Expression lastMember = pe; 

    for (int i = 0; i < properties.Length; i++) 
    { 
     MemberExpression member = Expression.Property(lastMember, properties[i]); 
     lastMember = member; 
    } 

    Expression valueExpression = Expression.Constant(value); 
    Expression equalityExpression = Expression.Equal(lastMember, valueExpression); 
    Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(equalityExpression, pe); 
    return lambda; 
} 

использовать его как:

Expression exp = GetEquality<Person>("Foo", "Address", "Name"); 

Где Foo твой Peter (так что значение, которое должно быть сравнены) , а Address и Name - это имена «цепочки» свойств. Например, я использую

public class Person 
{ 
    public Address Address { get; set; } 
} 

public class Address 
{ 
    public string Name { get; set; } 
} 

Таким образом, выражение генерируемого

source.Address.Name == "Foo" 

Если вы хотите использовать что-то вроде Address.Name, вы можете использовать метод как

Expression exp = GetEquality<Person>("Foo", "Address.Name".Split('.')); 
+0

Это выглядит многообещающим - я должен попробовать его, чтобы полностью его понять :-) Какой тип TSource был бы (мой родительский класс?) ?? –

+0

@ PeterLarsen'CPH 'То, что вы назвали 'T' в' typeof (T) '. Я назвал его «TSource», потому что в версии 0.1 кода были значения «TSource» и «TTarget». Тогда «TTarget» был удален :) – xanatos

+0

Хорошо, позвольте мне попробовать. Спасибо до сих пор :-) –

 Смежные вопросы

  • Нет связанных вопросов^_^