I want to create a factory that will create commonly mocked objects for my unit tests. I've already managed to set up my tests so I can mock up a Linq2Sql DataContext and return an in memory table instead of hitting the database. I set it up like this:
_contactsTable = new InMemoryTable<Contact>(new List<Contact>());
_contactEmailsTable = new InMemoryTable<ContactEmail>(new List<ContactEmail>());
// repeat this for each table in the ContactsDataContext
var mockContext = new Mock<ContactsDataContext>();
mockContext.Setup(c => c.Contacts).Returns(_contactsTable);
mockContext.Setup(c => c.ContactEmails).Returns(_contactEmailsTable);
// repeat this for each table in the ContactsDataContext
This gets tedious if the DataContext contains a lot of tables, so I thought a simple factory method that used reflection to get all the tables off the DataContext might help:
public static DataContext GetMockContext(Type contextType)
{
var instance = new Mock<DataContext>();
var propertyInfos = contextType.GetProperties();
foreach (var table in propertyInfos)
{
//I'm only worried about ITable<> now, otherwise skip it
if ((!table.PropertyType.IsGenericType) ||
table.PropertyType.GetGenericTypeDefinition() != typeof (ITable<>)) continue;
//Determine the generic type of the ITable<>
var TableType = GetTableType(table);
//Create a List<T> of that type
var emptyList = CreateGeneric(typeof (List<>), TableType);
//Create my InMemoryTable<T> of that type
var inMemoryTable = CreateGeneric(typeof (InMemoryTable<>), TableType, emptyList);
//NOW SETUP MOCK TO RETURN THAT TABLE
//How do I call instance.Setup(i=>i.THEPROPERTYNAME).Returns(inMemoryTable) ??
}
return instance.Object;
}
So far I've figured out how to create the objects I need to setup for the Mock, but I just can't figure out how to dynamically call Moq's Setup() passing in the property names. I started looking at reflection to Invoke() Moq's Setup() method, but it got really ugly fast.
Does anyone have a simple way to dynamically call Setup() and Returns() like this?
Edit: Brian's answer got me there. Here's how it works:
public static DataContext GetMockContext<T>() where T: DataContext
{
Type contextType = typeof (T);
var instance = new Mock<T>();
var propertyInfos = contextType.GetProperties();
foreach (var table in propertyInfos)
{
//I'm only worried about ITable<> now, otherwise skip it
if ((!table.PropertyType.IsGenericType) ||
table.PropertyType.GetGenericTypeDefinition() != typeof(ITable<>)) continue;
//Determine the generic type of the ITable<>
var TableType = GetTableType(table);
//Create a List<T> of that type
var emptyList = CreateGeneric(typeof(List<>), TableType);
//Create my InMemoryTable<T> of that type
var inMemoryTable = CreateGeneric(typeof(InMemoryTable<>), TableType, emptyList);
//NOW SETUP MOCK TO RETURN THAT TABLE
var parameter = Expression.Parameter(contextType);
var body = Expression.PropertyOrField(parameter, table.Name);
var lambdaExpression = Expression.Lambda<Func<T, object>>(body, parameter);
instance.Setup(lambdaExpression).Returns(inMemoryTable);
}
return instance.Object;
}
What you are looking for are Linq Expressions. Here is a sample of building a property accessory expression in action.
Using this class:
public class ExampleClass
{
public virtual string ExampleProperty
{
get;
set;
}
public virtual List<object> ExampleListProperty
{
get;
set;
}
}
The following tests demonstrate accessing its properties dynamically using the Linq.Expression classes.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void SetupDynamicStringProperty()
{
var dynamicMock = new Mock<ExampleClass>();
//Class type
var parameter = Expression.Parameter( typeof( ExampleClass ) );
//String rep of property
var body = Expression.PropertyOrField( parameter, "ExampleProperty" );
//build the lambda for the setup method
var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter );
dynamicMock.Setup( lambdaExpression ).Returns( "Works!" );
Assert.AreEqual( "Works!", dynamicMock.Object.ExampleProperty );
}
[TestMethod]
public void SetupDynamicListProperty_IntFirstInList()
{
var dynamicMock = new Mock<ExampleClass>();
var parameter = Expression.Parameter( typeof( ExampleClass ) );
var body = Expression.PropertyOrField( parameter, "ExampleListProperty" );
var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter );
var listOfItems = new List<object> { 1, "two", DateTime.MinValue };
dynamicMock.Setup( lambdaExpression ).Returns( listOfItems );
Assert.AreEqual( typeof( int ), dynamicMock.Object.ExampleListProperty[0].GetType() );
Assert.AreEqual( 1, dynamicMock.Object.ExampleListProperty[0] );
Assert.AreEqual( 3, dynamicMock.Object.ExampleListProperty.Count );
}
[TestMethod]
public void SetupDynamicListProperty_StringSecondInList()
{
var dynamicMock = new Mock<ExampleClass>();
var parameter = Expression.Parameter( typeof( ExampleClass ) );
var body = Expression.PropertyOrField( parameter, "ExampleListProperty" );
var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter );
var listOfItems = new List<object> { 1, "two" };
dynamicMock.Setup( lambdaExpression ).Returns( listOfItems );
Assert.AreEqual( typeof( string ), dynamicMock.Object.ExampleListProperty[1].GetType() );
Assert.AreEqual( "two", dynamicMock.Object.ExampleListProperty[1] );
Assert.AreEqual( 2, dynamicMock.Object.ExampleListProperty.Count );
}
}
EDIT
You are taking a step too far with this code. This code is creating a method with the signature of the lambda you want and then it's executing it (.Invoke). You are then trying to pass the result of the object (hence the compile error) into the setup for Moq. Moq will do the method execution and hookup for you once you tell it how to act (hence the lambda). If you use the lambda expression creation that I provided, it will build what you need.
var funcType = typeof (Func<>).MakeGenericType(new Type[] {TableType, typeof(object)});
var lambdaMethod = typeof (Expression).GetMethod("Lambda");
var lambdaGenericMethod = lambdaMethod.MakeGenericMethod(funcType);
var lambdaExpression = lambdaGenericMethod.Invoke(body, parameter);
//var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>(body, parameter); // FOR REFERENCE FROM BRIAN'S CODE
instance.Setup(lambdaExpression).Returns(inMemoryTable);
Do this instead
var parameter = Expression.Parameter( TableType );
var body = Expression.PropertyOrField( parameter, "PutYourPropertyHere" );
var lambdaExpression = Expression.Lambda<Func<ExampleClass, object>>( body, parameter );
instance.Setup(lambdaExpression).Returns(inMemoryTable);
EDIT
Took a stab at correcting the GetMockContext. Please note the few changes (I marked each line). I think this is closer. I am wondering, does InMemoryTable inherit from DataContext? If not, the method signature will be incorrect.
public static object GetMockContext<T>() where T: DataContext
{
Type contextType = typeof (T);
var instance = new Mock<T>(); //Updated this line
var propertyInfos = contextType.GetProperties();
foreach (var table in propertyInfos)
{
//I'm only worried about ITable<> now, otherwise skip it
if ((!table.PropertyType.IsGenericType) ||
table.PropertyType.GetGenericTypeDefinition() != typeof(ITable<>)) continue;
//Determine the generic type of the ITable<>
var TableType = GetTableType(table);
//Create a List<T> of that type
var emptyList = CreateGeneric(typeof(List<>), TableType);
//Create my InMemoryTable<T> of that type
var inMemoryTable = CreateGeneric(typeof(InMemoryTable<>), TableType, emptyList);
//NOW SETUP MOCK TO RETURN THAT TABLE
var parameter = Expression.Parameter(contextType);
var body = Expression.PropertyOrField(parameter, table.Name);
var lambdaExpression = Expression.Lambda<Func<T, object>>(body, parameter);
instance.Setup(lambdaExpression).Returns(inMemoryTable);
}
return instance.Object; //had to change the method signature because the inMemoryTable is not of type DataContext. Unless InMemoryTable inherits from DataContext?
}
I hope this helps!
Related
What I have:
public class HubGroup: HubObject
{
public HubGroup(elnGroup group)
{//do stuff}
}
public class elnGroup: elnObject
{
//has properties
}
My requirement is when I give 2 types to a method, it will generate a function that will accept object of elnGroup as a parameter and return a new Instance of HubGroup. I tried a lot of things but I couldn't find a way that I can do it fast (these generator functions will be running several times)
I know you will say use generics but my Types are generated at runtime. All I have is the Base classes for both the Types which I can explicity declare. The code you see below is bits of pieces i have, just to give u a heads up of what I happening.
So I call it like:
public class ApiDataHandler
{
//this will be called by a method to give json content for objEln
public void SoFunny<T>(string strContent, T objHub) where T : HubObject
{
if (typeof(T) == typeof(HubGroup))
{
if (string.IsNullOrEmpty(strContant))
{
throw new Exception("Cannot parse null/empty string! ---ApiDataHandler---");
}
var objEln = JsonConvert.DeserializeObject<elnGroup>(strContant);
GetHubObjectGenerator(objEln.GetType(), objHub.GetType());
}
}
}
What I want to create:
Func<object,object> generator = (input) => {var bObj = input as BObject;
var aObj = new AObject(bObj);
return aObj;
}
I have done this: but it keeps saying:
InvalidOperationException: variable 'objEln' of type 'ElnHub.HubObjectModel.elnGroup' referenced from scope '', but it is not defined
//also inside ApiData Handler class
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
ParameterExpression inputParam = Expression.Parameter(typeof(object), "input");
ParameterExpression objCastedAsEln = Expression.Parameter(elnObjectType, "objEln");
ParameterExpression objHub = Expression.Parameter(hubObjectType, "objHub");
var cast = Expression.TypeAs(inputParam, elnObjectType);
var assignCast = Expression.Assign(objCastedAsEln, cast);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var callingConstructor = Expression.New(constructor, new[] { objCastedAsEln });
var assignNewObj = Expression.Assign(objHub, callingConstructor);
var bodyBlock = Expression.Block(new[] { inputParam },
assignCast,
assignNewObj,
objHub
);
var l = Expression.Lambda<Func<object, object>>(
bodyBlock,
inputParam
);
Func<object, object> HubObjectGenerator = l.Compile();
return HubObjectGenerator;
}
I have also tried this where i send generic types, but couldnt find my way. A bit lost here:
public Func<T,T1> GetHubObjectGenerator<T,T1>() where T : elnObject where T1 : HubObject
{
ParameterExpression argParam = Expression.Parameter(typeof(T), "objEln");
var constructor = typeof(T1).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,null,new[] { typeof(T) },null);
Func<T, T1> HubObjectGenerator = Expression.Lambda<Func<T, T1>>(
Expression.New(constructor, new[] { argParam, }),
argParam
).Compile();
return HubObjectGenerator;
}
You want to write something like:
Func<object,object> generator = (input) =>
{
return new AObject((BObject)input);
}
You need something like:
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
var inputParameter = ExpressionParameter(typeof(object), "input");
var castInput = Expression.Convert(inputParameter, elnObjectType);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var instantiation = Expression.New(constructor, castInput);
var lambda = Expression.Lambda<Func<object, object>>(instantiation, inputParameter);
return lambda.Compile();
}
You can use generics here easily also, you don't even need a cast:
public Func<THub, TEln> GetHubObjectGenerator<THub, TEln>() where THub : HubObject, TEln : elnObject
{
var inputParameter = ExpressionParameter(typeof(TEln), "input");
var constructor = typeof(THub).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(TEln) }, null);
var instantiation = Expression.New(constructor, inputParameter);
var lambda = Expression.Lambda<Func<THub, TEln>>(instantiation, inputParameter);
return lambda.Compile();
}
I didn't use variables or Expression.Block here, as there's no need. If you did want to create intermediate variables, use Expression.Variable (Expression.Parameter is for input parameters only). Something like:
public Func<object, object> GetHubObjectGenerator(Type elnObjectType, Type hubObjectType)
{
var inputParameter = ExpressionParameter(typeof(object), "input");
var castInputVar = Expression.Variable(elnObjectType, "eln");
var castInput = Expression.Convert(inputParameter, elnObjectType);
var castInputAssign = Expression.Assign(castInputVar, castInput);
var constructor = hubObjectType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { elnObjectType }, null);
var hubObjectVar = Expression.Variable(hubObjectType, "hub");
var instantiation = Expression.New(constructor, castInputVar);
var hubObjectAssign = Expression.Assign(hubObjectVar, instantiation);
var block = Expression.Block(new[] { castInputVar, hubObjectVar },
castInputAssign,
hubObjectAssign,
hubObject);
var lambda = Expression.Lambda<Func<object, object>>(block, inputParameter);
return lambda.Compile();
}
I'm trying to create a mock dynamically based on xml data. This works fine for most types, but enums turn out to be a bit tricky. The ??? in my code expects the type of the enum. But obviously the type is not known at compile time, so I'll have to resort to reflection. I'll probably have to use MakeGenericMethod to invoke Expression.Lambda directly or indirectly, but that seems to just move the problem as mock.Setup expects a compile time type as well. That's where I get stuck. Any help is appreciated.
public static Mock<T> DeserializeMock<T>(XElement node)
where T : class
{
var mock = new Mock<T>();
foreach (var property in PropertyInfoHelper.EnumeratePublicAndInternalProperties(typeof(T)))
{
var attribute = node.Attribute(property.Name);
if (property.PropertyType == typeof(string))
{
var parameter = Expression.Parameter(typeof(T));
var body = Expression.PropertyOrField(parameter, property.Name);
var propertyExpression = Expression.Lambda<Func<T, string>>(body, parameter);
mock.Setup(propertyExpression).Returns(attribute.Value);
}
// ... other types omitted for brevity...
else if (property.PropertyType.IsEnum)
{
var parameter = Expression.Parameter(typeof(T));
var body = Expression.PropertyOrField(parameter, property.Name);
var propertyExpression = Expression.Lambda<Func<T, ???>>(body, parameter);
mock.Setup(propertyExpression).Returns(convertToEnum(attribute.Value, property.PropertyType));
}
}
return mock;
}
You would end up having to use reflection to get the types for the setup
//...omitted for brevity...
else if (property.PropertyType.IsEnum) {
var parameter = Expression.Parameter(typeof(T));
var body = Expression.PropertyOrField(parameter, property.Name);
var delegateType = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
var propertyExpression = Expression.Lambda(delegateType, body, parameter);
var value = convertToEnum(attribute.Value, property.PropertyType);
var setup = mock.GetType().GetMethods()
.FirstOrDefault(m => m.Name == "Setup" && m.ContainsGenericParameters)
.MakeGenericMethod(property.PropertyType);
var result = setup.Invoke(mock, new object[] { propertyExpression });
var returns = result.GetType().GetMethod("Returns", new[] { property.PropertyType });
returns?.Invoke(result, new object[] { value });
}
//...omitted for brevity...
I also assume based on the original code that all the members being setup on the mock are either virtual or abstract members.
Proof of concept
[TestClass]
public class MyTestClass {
[TestMethod]
public void MyTestMethod() {
//Arrange
XElement element = new XElement("root",
new XAttribute("MyProperty1", "Hello World"),
new XAttribute("MyEnumProperty", "Value2")
);
//Act
var mock = DeserializeMock<MyClass>(element);
//Assert
var actual = mock.Object;
actual.MyEnumProperty.Should().Be(MyEnum.Value2);
actual.MyProperty1.Should().Be("Hello World");
}
public class MyClass {
public virtual string MyProperty1 { get; set; }
public virtual MyEnum MyEnumProperty { get; set; }
}
public enum MyEnum {
Value1,
Value2
}
//...
}
I've got an function which generates an expression to filter a table by it's primary key, when passed in an Object[], this is very similar to Find function except that it doesn't materialize so you can pass an IQueryable around afterwards
public static Expression<Func<T, bool>> FilterByPrimaryKeyPredicate<T>(this DbContext dbContext, object[] id)
{
var keyProperties = dbContext.GetPrimaryKeyProperties<T>();
var parameter = Expression.Parameter(typeof(T), "e");
var body = keyProperties
// e => e.{propertyName} == new {id = id[i]}.id
.Select((p, i) => Expression.Equal(
Expression.Property(parameter, p.Name),
Expression.Convert(
Expression.PropertyOrField(Expression.Constant(new { id = id[i] }), "id"),
p.ClrType)))
.Aggregate(Expression.AndAlso);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
This works by first getting the primary keys for a table, it creates binary expression foreach property, the Id is wrapped in an anonymous type to leverage the query cache. This is working fine. However, I'd like to take this a step further.
I'd like to preserve the Expression so I don't have to generate it each time I pass on a new set of ids, How can I store this Expression while still leveraging the Query Cache?
Edit TL;DR
So I'm attempt to cache it using array access in a static class as suggest, however I'm encountering an error:
public class PrimaryKeyFilterContainer<T>
{
const string ANON_ID_PROP = "id";
static Expression<Func<T, bool>> _filter;
Type ANON_TYPE = new { id = (object)0 }.GetType();
public object[] id { get; set; }
public PrimaryKeyFilterContainer()
{
}
public Expression<Func<T, bool>> GetFilter(DbContext dbContext, object[] id)
{
this.id = id;
if(null == _filter)
{
var keyProperties = dbContext.GetPrimaryKeyProperties<T>();
var parameter = Expression.Parameter(typeof(T), "e");
var body = keyProperties
// e => e.PK[i] == id[i]
.Select((p, i) => Expression.Equal(
Expression.Property(parameter, p.Name),
Expression.Convert(BuildNewExpression(i),
p.ClrType)))
.Aggregate(Expression.AndAlso);
_filter = Expression.Lambda<Func<T, bool>>(body, parameter);
}
return _filter;
}
NewExpression BuildNewExpression(int index)
{
var currentObject = Expression.Constant(this);
var fieldAccess = Expression.PropertyOrField(currentObject, nameof(id));
var arrayAccess = Expression.ArrayAccess(fieldAccess, Expression.Constant(index));
return Expression.New(ANON_TYPE.GetConstructor(new[] { typeof(object) }), arrayAccess);
}
}
No coercion operator is defined between types '<>f__AnonymousType0`1[System.Object]' and 'System.Int32'
I'm getting closer but I'm not sure if it's going to work still.
As I mentioned in the comments, the main problem is that we cannot use array index access inside the expression tree - EF6 throws not supported exception and EF Core turns it into client evaluation.
So we need to store the keys in a class with dynamic count of properties and property types. Fortunately the System.Tuple generic classes provide such functionality, and can be used in both EF6 and EF Core.
Following is a class that implements the above idea:
public class PrimaryKeyFilter<TEntity>
where TEntity : class
{
object valueBuffer;
Func<object[], object> valueArrayConverter;
public PrimaryKeyFilter(DbContext dbContext)
{
var keyProperties = dbContext.GetPrimaryKeyProperties<TEntity>();
// Create value buffer type (Tuple) from key properties
var valueBufferType = TupleTypes[keyProperties.Count - 1]
.MakeGenericType(keyProperties.Select(p => p.ClrType).ToArray());
// Build the delegate for converting value array to value buffer
{
// object[] values => new Tuple(values[0], values[1], ...)
var parameter = Expression.Parameter(typeof(object[]), "values");
var body = Expression.New(
valueBufferType.GetConstructors().Single(),
keyProperties.Select((p, i) => Expression.Convert(
Expression.ArrayIndex(parameter, Expression.Constant(i)),
p.ClrType)));
valueArrayConverter = Expression.Lambda<Func<object[], object>>(body, parameter).Compile();
}
// Build the predicate expression
{
var parameter = Expression.Parameter(typeof(TEntity), "e");
var valueBuffer = Expression.Convert(
Expression.Field(Expression.Constant(this), nameof(this.valueBuffer)),
valueBufferType);
var body = keyProperties
// e => e.{propertyName} == valueBuffer.Item{i + 1}
.Select((p, i) => Expression.Equal(
Expression.Property(parameter, p.Name),
Expression.Property(valueBuffer, $"Item{i + 1}")))
.Aggregate(Expression.AndAlso);
Predicate = Expression.Lambda<Func<TEntity, bool>>(body, parameter);
}
}
public Expression<Func<TEntity, bool>> Predicate { get; }
public void SetValues(params object[] values) =>
valueBuffer = valueArrayConverter(values);
static readonly Type[] TupleTypes =
{
typeof(Tuple<>),
typeof(Tuple<,>),
typeof(Tuple<,,>),
typeof(Tuple<,,,>),
typeof(Tuple<,,,,>),
typeof(Tuple<,,,,,>),
typeof(Tuple<,,,,,,>),
typeof(Tuple<,,,,,,,>),
};
}
You can create and store an instance of the class. Then use the expression returned by the Predicate property inside the query. And SetValues method to set the parameters.
The drawback is that the value storage is bound to the class instance, hence it cannot be used concurrently. The original approach works well in all scenarios, and the performance impact IMO should be negligible, so you might consider staying on it.
I am trying to write a dynamic select statement. I have the following:
public class MainList
{
public string Prop1{ get; set; }
public string Prop2{ get; set; }
public string Prop3{ get; set; }
}
public class SearchObject
{
public string Prop1{ get; set; }
}
I want build the expression like the following
var newList = MainList.Select(n => new SearchObject { Prop1 = n.Prop1});
The code I am using creates a list based on MainList. I then create the select expression by passing the SearchObject type and the parameters I want to populate, for now. It runs until the second to last line.
public void Start()
{
List<MainList> newList = new List<MainList>(); //This has a ton list objects
var result = newList.Select(CreateSelect<SearchObject>("Prop1"));
}
public static Func<MainList, T> CreateSelect<T>(string fields)
{
var par = Expression.Parameter(typeof(T), "n");
var newInstance= Expression.New(typeof(T));
var bindings = fields.Split(',').Select(o => o.Trim())
.Select(n => {
var p = typeof(T).GetProperty(n);
var original = Expression.Property(par, p);
return Expression.Bind(p, original);
}
);
var newT= Expression.MemberInit(newInstance, bindings);
var lambda = Expression.Lambda<Func<MainList, T>>(newT, par); //ERROR HAPPENS HERE
return lambda.Compile();
}
The error I get is:
Additional information: ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList'
I am unsure on the meaning of the error and also how to resolve the issue.
The first issue is, as already mentioned by Jeroen van Langen, the type of the parameter must be MainList.
The second issue is the usage of the Expression.Bind. Since the source and target are different types, you cannot use one and the same PropertyInfo. The first argument must be a PropertyInfo of the target type T, while the second - expression coming from the source type MainList (in your case, Expression.Property on the parameter with the specified property name).
The correct implementation is something like this:
public static Func<MainList, T> CreateSelect<T>(string fields)
{
var parameter = Expression.Parameter(typeof(MainList), "n");
var bindings = fields.Split(',')
.Select(name => name.Trim())
.Select(name => Expression.Bind(
typeof(T).GetProperty(name),
Expression.Property(parameter, name)
));
var newT = Expression.MemberInit(Expression.New(typeof(T)), bindings);
var lambda = Expression.Lambda<Func<MainList, T>>(newT, parameter);
return lambda.Compile();
}
The exception ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList' explained:
Meaning: There is a mismatch between the ParameterExpression type typeof(T) and the Expression.Lambda Func<MainList, T> --> MainList
Your:
var par = Expression.Parameter(typeof(T), "n");
should be:
var par = Expression.Parameter(typeof(MainList), "n");
i'm starting to explore dynamic expressions, so please help me to solve one issue.
I have an object
public class Categorisation{
string Name{get;set;}
}
public class Client{
public Categorisation Categorisation{get;set;}
}
All I need is to write a dynamic expression and call Categorisation.Name.Equals("A1") from Client object.
x=>x.Categorisation.Name.Equals("A1")
How can I do this using Expressions?
var param = Expression.Parameter(typeof(Client));
var prop = Expression.Property(param, typeof(Client).GetProperty("Categorisation"));
var argument = Expression.Constant("A1");
var method = typeof(string).GetMethod("Equals", new[] { typeof(string) });
var call = Expression.Call(prop, method);
var expr = Expression.Lambda<Func<Client, bool>>(call, param);
Of course this code is wrong and I call method Equals from Categorisation property and not from Name of Categorisation. But how to invoke Name property?
var param = Expression.Parameter(typeof(Client));
var prop = Expression.Property(param, typeof(Client).GetProperty("Categorisation"));
var namePropExpr = Expression.Property(prop, "Name");
var argument = Expression.Constant("A1");
var method = typeof(string).GetMethod("Equals", new[] { typeof(string) });
var call = Expression.Call(namePropExpr, method, argument);
var expr = Expression.Lambda<Func<Client, bool>>(call, param);