Linq query - use string as property? - c#

Code:
foreach (PropertyInfo prop in typeof(SomeObject).GetProperties())
{
if (Attribute.IsDefined(prop, typeof(SomeCustomAttribute)))
{
column.Expression(p => p.Name);
}
}
I want to add columns which have SomeCustomAttribute data-annotation assigned.
How to use prop.Name (name of the property) as an property instead of manual p.Name?
For example..
...
column.Expression(p => prop.Name);
...
column.Expression is
ITableColumn Expression<TProperty>(Expression<Func<TModel, TProperty>> expression)

Suppose you have this types defined:
interface ITableColumn { }
class SomeObject
{
public int MyProperty { get; set; }
}
class Column<TModel>
{
public ITableColumn Expression<TProperty>(Expression<Func<TModel, TProperty>> expression)
{
// just a stub
return null;
}
}
To invoke Column.Expression for single property, obtained via reflection, you have to build member expression first:
private static LambdaExpression MakeMemberExpression(PropertyInfo propertyInfo)
{
var instanceExpression = Expression.Parameter(propertyInfo.DeclaringType);
return Expression.Lambda(Expression.MakeMemberAccess(instanceExpression, propertyInfo), instanceExpression);
}
As long as you don't know TProperty statically, you don't need to build strongly typed lambda (Expression<Func<TModel, TProperty>>).
Now, let's invoke it:
var property = typeof(SomeObject)
.GetProperty("MyProperty");
var columnType = typeof(Column<>)
.MakeGenericType(typeof(SomeObject));
var expressionMethod = columnType
.GetMethod("Expression")
.MakeGenericMethod(property.PropertyType);
var expr = MakeMemberExpression(property);
expressionMethod.Invoke(new Column<SomeObject>(), new[] { expr });
Hope this helps.

Related

How to retrieve a property of an object from a string?

In order to use it as a selector in a Grouping Clause at runtime, I want basically retrieve a property from an object T by passing its name. Example with this class:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
}
I want to use my method like this:
private void MyMethod(string propertyName)
{
var lambda = GetLambdaExpression(propertyName);
// The problem is to specify the Type at compile time...
var selector = GetLambdaSelector<DateTime>(lambda); // Seems mandatory to convert LambdaExpression to Expression<Func<Person, T>> to use in a grouping clause
var result = emps.GroupBy(
selector.Compile(),
p => p.Birthday,
(key, g) => new { PersonName = key, = g.ToList() }).AsQueryable();
}
Here are methods statements :
LambdaExpression GetLambdaExpression(string propertyName)
{
var type = typeof(Person);
var propertyInfo = type.GetProperty(propertyName);
var propertyType = propertyInfo.PropertyType;
var entityType = propertyInfo.DeclaringType;
var parameter = Expression.Parameter(entityType, "entity");
var property = Expression.Property(parameter, propertyInfo);
var funcType = typeof(Func<,>).MakeGenericType(entityType, propertyInfo.PropertyType);
var lambda = Expression.Lambda(funcType, property, parameter);
return lambda;
}
Expression<Func<Person, T>> GetLambdaSelector<T>(LambdaExpression expression)
{
return (Expression<Func<Person, T>>)expression;
}
I'm stuck because I want to resolve the type (DateTimein the example) at runtime and not at compile time.
So how to call this method with type resolve at runtime:
GetLambdaSelector<?>(lambda); ?
Or maybe can I change the signature of LambdaExpression GetLambdaExpression(string propertyName) to Expression<Func<Person, T>> with reflection but I did not manage it for the moment. ?

How to write a generic mock which maps interface properties to key-value pairs in c# using moq

I want to write a method which creates mocks for any interface.
public T GetMock<T>(IDictionary<string, object> data) where T : class
I care only about property getters first. All getters should return values which are stored in the dictionary. Property name is a key in this dictionary. Following code illustrates intended usage:
public interface IFoo
{
string Property1 { get; }
int Property2 { get; }
DateTime Property3 { get; }
}
[Test]
public void TestY()
{
var data = new Dictionary<string, object>
{
{"Property1", "Hello"},
{"Property2", 5},
{"Property3", DateTime.Today}
};
var mock = GetMock<IFoo>(data);
Assert.AreEqual("Hello", mock.Property1);
Assert.AreEqual(5, mock.Property2);
Assert.AreEqual(DateTime.Today, mock.Property3);
}
The point is that I want to mock ANY interface. So my generic mock crreation looks like:
public T GetMock<T>(IDictionary<string, object> data) where T : class
{
var mock = new Mock<T>();
var type = typeof(T);
var properties = type.GetProperties();
foreach (var property in properties)
{
var attributeName = property.Name;
var parameter = Expression.Parameter(type);
var body = Expression.Property(parameter, attributeName);
var lambdaExpression = Expression.Lambda<Func<T, object>>(body, parameter);
Func<object> getter = () => data[attributeName];
mock.Setup(lambdaExpression).Returns(getter);
}
return mock.Object;
}
It should work but there is an issue with type conversion. The test fails with a message:
System.ArgumentException : Expression of type 'System.Int32' cannot be
used for return type 'System.Object'
I guess I am missing some conversion lambda. Any suggestions how to fix the problem?
Guess the only option is to use Reflection, because current version is 4.2, but still - there's no "Mock.Setup(Expression expr)" implementation, as stated Patrick.
So, here's my sample:
public static class ConfigFactory<T> where T : class {
static T cachedImplInstance;
public static T BuildConfigGroupWithReflection() {
if (cachedImplInstance == null) {
Type interfaceType = typeof(T);
MethodInfo setupGetMethodInfo = typeof(Mock<T>).GetMethod("SetupGet");
Mock<T> interfaceMock = new Mock<T>();
IDictionary<Type, MethodInfo> genericSetupGetMethodInfos = new Dictionary<Type, MethodInfo>();
IDictionary<Type, MethodInfo> specificReturnsMethodInfos = new Dictionary<Type, MethodInfo>();
if (setupGetMethodInfo != null)
foreach (PropertyInfo interfaceProperty in interfaceType.GetProperties()) {
string propertyName = interfaceProperty.Name;
Type propertyType = interfaceProperty.PropertyType;
ParameterExpression parameter = Expression.Parameter(interfaceType);
MemberExpression body = Expression.Property(parameter, propertyName);
var lambdaExpression = Expression.Lambda(body, parameter);
MethodInfo specificSetupGetMethodInfo =
genericSetupGetMethodInfos.ContainsKey(propertyType) ?
genericSetupGetMethodInfos[propertyType] :
genericSetupGetMethodInfos[propertyType] = setupGetMethodInfo.MakeGenericMethod(propertyType);
object setupResult = specificSetupGetMethodInfo.Invoke(interfaceMock, new[] { lambdaExpression });
MethodInfo returnsMethodInfo =
specificReturnsMethodInfos.ContainsKey(propertyType) ?
specificReturnsMethodInfos[propertyType] :
specificReturnsMethodInfos[propertyType] = setupResult.GetType().GetMethod("Returns", new[] { propertyType });
if (returnsMethodInfo != null)
returnsMethodInfo.Invoke(setupResult, new[] { Settings.Default[propertyName] });
}
cachedImplInstance = interfaceMock.Object;
}
return cachedImplInstance;
}
}
Notice line "returnsMethodInfo.Invoke(setupResult, new[] { Settings.Default[propertyName] });" - you may put your dictionnary here.
Say, we have interface:
public interface IConfig {
string StrVal { get; }
int IntVal { get; }
StringCollection StrsVal { get; }
string DbConnectionStr { get; }
string WebSvcUrl { get; }
}
Then, usage is as follows (assuming we have "Settings" of our project with corresponding Names/Types/Values):
IConfig cfg0 = ConfigFactory<IConfig>.BuildConfigGroupWithReflection();
This is a half answer, since I don't see any support in Moq for doing this. To get the correct Func, do the following:
// In your for loop from above...
var attributeName = property.Name;
var parameter = Expression.Parameter(type);
var body = Expression.Property(parameter, attributeName);
// Add this line to create the correct Func type
var func = typeof(Func<,>).MakeGenericType(typeof(T), property.PropertyType);
// Then use this Func to create the lambda
var lambdaExpression = Expression.Lambda(func, body, parameter);
The problem is that Setup doesn't have an overload that allows you to pass in a non-generic expression that represents a Func. In otherwords, this won't compile:
// Error: cannot convert from 'System.Linq.Expressions.LambdaExpression'
// to 'System.Linq.Expressions.Expression<System.Action<T>>'
mock.Setup(lambdaExpression);
So at this point you're stuck.
You could submit an issue (or pull request) to the Moq project, though I don't know if this application has a wide enough audience...

Entity Framework DbSet dynamic query

I am creating a DbSet from a Type that is passed in and I need to query the database for a dynamic field and value. Using generics I would use the where function with a lambda expression. Can this be achieved from a standard dbSet created as follows ?
DbSet table = dataContext.Set(EntityType);
PropertyInfo propertyInfo = EntityType.GetProperty(PropertyName);
// Expression: "entity"
ParameterExpression parameter = Expression.Parameter(EntityType, "entity");
// Expression: "entity.PropertyName"
MemberExpression propertyValue = Expression.MakeMemberAccess(parameter, propertyInfo);
// Expression: "value"
object convertedValue = Convert.ChangeType(value, propertyInfo.PropertyType);
ConstantExpression rhs = Expression.Constant(convertedValue);
// Expression: "entity.PropertyName == value"
BinaryExpression equal = Expression.Equal(propertyValue, rhs);
// Expression: "entity => entity.PropertyName == value"
LambdaExpression lambda = Expression.Lambda(equal, parameter);
Now need to query the table to get data.
There is a nuget package called 'System.Linq.Dynamic'.
http://dynamiclinq.codeplex.com/
This package allows you to form statements against DbSets using strings, like this:
myContext.MyDbSet.Where("PropertyName == #0", "aValue");
It is possible to do this, with Expressions as you suggest in your question, but this library takes out all the heavy lifting.
I've used this with great success in one of my previous projects.
You can try something like the following:
public class UniqueRecordValidationAttribute : ValidationAttribute
{
public IValidationAttribute DynamicInstance { get; private set; }
public UniqueRecordValidationAttribute(Type type,
params object[] arguments )
{
DynamicInstance =
Activator.CreateInstance(type, arguments) as IValidationAttribute;
}
public override bool IsValid(object value)
{
return DynamicInstance.IsValid(value);
}
}
public class UniqueRecordValidator<C, E, P> : IValidationAttribute
where C : DataContext, new() where E : class
{
Func<E, P, bool> Check { get; set; }
public UniqueRecordValidator(Func<E, P, bool> check)
{
Check = check;
}
public bool IsValid(object value)
{
DataContext dataContext = new C();
Table<E> table = dataContext.GetTable<E>();
return table.Count(i => Check(i as E, (P)value)) == 0;
}
}
public interface IValidationAttribute
{
bool IsValid(object value);
}
and
[UniqueRecordValidation(
typeof(UniqueRecordValidator<AssetTrackingEntities, ATUser_Account, string>),
new Func<ATUser_Account, string, bool>((i, p) => i.User_Login == p))]
public string User_Name { get; set; }
This would be a completely strongly typed solution, but I am not shure the Func<E, P, bool> inside the Count is supported by EF as I could not test that here at the moment. But for LINQ to objects this code does work.
If this does not work you can at least improve it with generics and dynamic LINQ to the following:
public class UniqueRecordValidator<C, E> : IValidationAttribute
where C : DataContext, new() where E : class
{
string PropertyName { get; set; }
public UniqueRecordValidator(string propertyName)
{
PropertyName = propertyName;
}
public bool IsValid(object value)
{
DataContext dataContext = new C();
Table<E> table = dataContext.GetTable<E>();
return table.Count(PropertyName + " = #0", value) == 0;
}
}
[UniqueRecordValidation(
typeof(UniqueRecordValidator<AssetTrackingEntities, ATUser_Account>)
"User_Login")]
public string User_Login { get; set; }

TextareaFor on nullable types with reflection

public Expression GetValue<T>(T source, PropertyInfo property)
{
ParameterExpression fieldName = Expression.Parameter(pi.PropertyType, pi.Name);
Expression fieldExpr = Expression.PropertyOrField(Expression.Constant(source), pi.Name);
var exp = Expression.Lambda(typeof(Func<,>).MakeGenericType(typeof(T), fieldExpr.Type),
fieldExpr,
fieldName);
return exp;
}
Here is my calling function
public MvcHtmlString RenderModel(T model)
{
foreach (var prop in typeof(T).GetProperties())
{
var x = InputExtensions.TextBoxFor(h, (dynamic) GetValue<T>(model, prop));
}
return new MvcHtmlString(string.Empty);
}
Here is an example class:
public class Test
{
public int? ID { get; set; }
public string Name { get; set; }
public DateTime? Date{ get; set; }
}
I adopted GetValue from part of:
Member Expression cannot convert to object from nullable decimal
which seems to work quite well until you reach properties that are not of type object I get this error:
ParameterExpression of type 'System.Nullable`1[System.Int32]' cannot be used for delegate parameter of type 'Test'
I'm not really sure where I've gone wrong here, and what that error even means
If I understand correctly, you need property access lambda. Here is the correct version of GetValue<T> method:
public Expression GetValue<T>(T source, PropertyInfo pi)
{
var param = Expression.Parameter(typeof(T), "p");
Expression body = param;
body = Expression.PropertyOrField(body, pi.Name);
return Expression.Lambda(body, param);
}
If you want to make an Expression by providing a delegate (that in your question it is Func<T,..> ) then you have to provide the delegate type, body expression and parameter expressions too:
public Expression GetValue<T>(T source, PropertyInfo property)
{
return Expression.Lambda(
delegateType: typeof(Func<,>).MakeGenericType(typeof(T), pi.PropertyType),
body: Expression.PropertyOrField(Expression.Parameter(typeof(T), "x"), pi.Name),
parameters: Expression.Parameter(typeof(T), "x"));
}

How to bypass the need of specifing a generic parameter type?

I have an extension method like this one :
public static void ImplementsAttribute<TX, TY>(this Expression<Func<TY>> expression)
where TX : Coupling.PropertiesMergerAttribute
{
var memberExpression = expression.Body as MemberExpression;
var name = MetaHelper.GetPropertyName(expression);
var property = memberExpression.Expression.Type.GetProperty(name);
var attributes = property.GetCustomAttributes(true);
Assert.IsTrue(attributes.Any(a => a is TX));
}
I can actually use my code like this :
Expression<Func<String>> nameProperty = () => new ImprovisedExplosiveXML().Name;
nameProperty.ImplementsAttribute<Coupling.UnresolvablePropertiesMergerAttribute, String>();
but I would like to not need to specify the second generic parameter type :
Expression<Func<String>> nameProperty = () => new ImprovisedExplosiveXML().Name;
nameProperty.ImplementsAttribute<Coupling.UnresolvablePropertiesMergerAttribute>();
Is there a way of doing this in C# 3.5 ?
C# does not support partial generic inference. If the compiler can't determine all the types you have to supply them all yourself.
You can do something like this:
public class AttributeTester
{
public Attribute[] Attributes { get; set; }
public void ImplementsAttribute<TAttType>()
{
Assert.IsTrue(Attributes.Any(x => x is TAttType));
}
}
public static void ForProperty<TType, TProperty>(this TType obj, Expression<Func<TType, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
var name = MetaHelper.GetPropertyName(expression);
var property = memberExpression.Expression.Type.GetProperty(name);
return new AttributeTester { Attributes = property.GetCustomAttributes(true) };
}
Then, you should be able to just write it like so:
new ImproveisedExplosiveXML().ForProperty(x => x.Name).ImplementsAttribute<SomeAttribute>();

Categories