For example using this classes:
Public class InnerClass
{
string Value {get;set;}
}
public class ObjectClass
{
InnerClass Inner {get; set;}
}
And with a method like this:
public void SomeMethod<TObj, T>(Expression<Func<TObj, T>> exp) where T : InnerClass
{
// ??
}
I need to add "Value" property to the exp.
Calling the method:
SomeMethod(x => x.Inner);
I need to add value to the expression:
x => x.Inner.Value
Tell it what types you're using, otherwise it won't know:
SomeMethod<ObjectClass, InnerClass>(k => k.Inner);
Update your method to
public void SomeMethod<TObject>(Expression<Func<TObject, object>> exp)
{
.....
}
then you can access the property
SomeMethod<ObjectClass>(x => x.Inner.Value);
At the end this work for me:
public void SomeMethod<TObj, T>(Expression<Func<TObj, T>> exp) where T : InnerClass
{
var newExp = Expression.Lambda<Func<TObj, string>>(
Expression.PropertyOrField(exp.Body, "Value"),
exp.Parameters);
// now I can use newExp
}
From here: Adding a node/property to an Expression Tree
Related
Here is the example code:
public interface A
{
int MyProperty { get; set; }
}
public class B : A
{
public int MyProperty { get; set; }
}
public class C<T> where T : A
{
public Expression<Func<T, bool>> Expression { get; } = a => a.MyProperty > 0;
}
class Program
{
static void Main(string[] args)
{
var cExpression = new C<B>();
Console.WriteLine(cExpression.Expression.ToString());
}
}
The output of the expression: a => (Convert(a, A).MyProperty > 0)
And I decompiled the code above and I got below:
public class C<T> where T : A
{
public Expression<Func<T, bool>> Expression { get; } = (T a) => ((A)a).MyProperty > 0;
}
As you can see, the compiler added a cast option ((A)a) to the expression, that is what I DO NOT want, so the question is how can I tell the compiler NOT to do that?
There is no way to "tell the compiler" not to do this, but you can construct the expression tree directly:
public class C<T> where T : A {
private static readonly MethodInfo s_propGetter = typeof(A).GetProperty(nameof(A.MyProperty)).GetMethod;
public Expression<Func<T, bool>> Expr { get; private set; }
public C() {
var param = Expression.Parameter(typeof(T), "a");
Expr = Expression.Lambda(
typeof(Func<T, bool>),
Expression.GreaterThan(Expression.Property(param, s_propGetter), Expression.Constant(0)),
new[] {param}
) as Expression<Func<T, bool>>;
}
}
Looks like the compiler is emitting the Convert because of the possibility of the generic type parameter to be struct (value type), even though the manual approach demonstrated by another answer proves that it is unnecessary.
But is is what it is. So the only way currently to tell compiler to not generate Convert (cast) is to put class constraint:
where T : class, A
Now the output of the original sample expression will be a => (a.MyProperty > 0)
I want to create the class Foo as follows.
The Foo constructor input expression has to get some member of Type T to do some work.
class Foo<T>
{
public Foo<TResult>(Expression<Func<T, TResult>> selector)
{
List<string> memberNames = typeof(TR).GetProperties().Select(p => p.Name).ToList();
....//some work on memberNames
}
}
and create Foo<T> instance by this code:
Foo<ClassA> foo = new Foo<ClassA>(u=>new{u.Property1, u.Property2});
However, this did not work and gave the following error:
Constructor can't have Generic type TResult.
How can I fix this?
Edit:
After struggling to understand the expression I found an answer and have written it as an answer.
You can move the logic outside of consrtuctor to separate method. Instead of using constructor to create Foo - you can use static method, like this:
class Foo<T> {
private Foo() {
}
private void Init<TResult>(Expression<Func<T, TResult>> selector) {
List<string> memberNames = typeof(TResult).GetProperties().Select(p => p.Name).ToList();
//some work on memberNames
}
public static Foo<T> Create<TResult>(Expression<Func<T, TResult>> selector) {
var foo = new Foo<T>();
foo.Init(selector);
return foo;
}
}
And use it like this:
Foo<ClassA> foo = Foo<ClassA>.Create(u=>new{u.Property1, u.Property2});
I solve that as follow
class ClassA
{
public int MyProperty { get; set; }
public int MyProperty2 { get; set; }
}
class Foo<T>
{
public Foo(Expression<Func<T, Object>> selector)
{
var props = ((NewExpression)selector.Body).Members.Select(p => p.Name).ToList();
}
}
Foo<ClassA> foo = new Foo<ClassA>(u => new { u.MyProperty, u.MyProperty2 });
I am trying to create an extension method to list the properties in the lambda expression.
Let say there is a Class named Example
public class Example {
Public string Name {get;set;}
Public string Description {get;set;}
}
the extension method can be something like below
public static void GetProperties<T>(this T obj) where T : new()
{
}
Expected usage : this.GetProperties<Example>(m=>m.
so when i type m=>m. should display both the properties (Name,Description).
I think you need to used Func:
public static void GetProperties<T, V>(this T obj, Func<T, V selector) where T : new()
{
}
Usage:
Example ex = new Example();
ex.GetProperties(m => m.Name); // Func<Example, string>
ex.GetProperties(m => m.Description); // Func<Example, string>
I really didn't understand the expected behavior inside the method. But you mentioned m.Name and m.Description. So a property selector is your way.
Func<Example, string> is a function that accepts an Example input parameter and returns a string (which is the property in case of Name and Description).
public static class PropertyUtility
{
public static string GetPropertyName<T>(this T entity, Expression<Func<T, object>> exp)
{
if (exp.Body is MemberExpression) {
return ((MemberExpression)exp.Body).Member.Name;
}
else {
var op = ((UnaryExpression)exp.Body).Operand;
return ((MemberExpression)op).Member.Name;
}
}
}
And use like this:
Example ex = new Example();
var property = ex.GetPropertyName(x => x.Description);
I have two very simple objects:
public class CategoryDto
{
public string Id { get; set; }
public string MyValueProperty { get; set; }
}
public class Category
{
public string Id { get; set; }
[MapTo("MyValueProperty")]
public string Key { get; set; }
}
When mapping a Category to a CategoryDto with AutoMapper, I would like the following behavior:
The properties should be mapped as usual, except for those that have the MapTo attribute. In this case, I have to read the value of the Attribute to find the target property. The value of the source property is used to find the value to inject in the destination property (with the help of a dictionary). An example is always better that 1000 words...
Example:
Dictionary<string, string> keys =
new Dictionary<string, string> { { "MyKey", "MyValue" } };
Category category = new Category();
category.Id = "3";
category.Key = "MyKey";
CategoryDto result = Map<Category, CategoryDto>(category);
result.Id // Expected : "3"
result.MyValueProperty // Expected : "MyValue"
The Key property is mapped to the MyValueProperty (via the MapTo Attribute), and the assigned value is "MyValue", because the source property value is "MyKey" which is mapped (via dictionary) to "MyValue".
Is this possible using AutoMapper ? I need of course a solution that works on every object, not just on Category/CategoryDto.
I finally (after so many hours !!!!) found a solution.
I share this with the community; hopefully it will help someone else...
Edit: Note that it's now much simpler (AutoMapper 5.0+), you can do like I answered in this post: How to make AutoMapper truncate strings according to MaxLength attribute?
public static class Extensions
{
public static IMappingExpression<TSource, TDestination> MapTo<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
Type sourceType = typeof(TSource);
Type destinationType = typeof(TDestination);
TypeMap existingMaps = Mapper.GetAllTypeMaps().First(b => b.SourceType == sourceType && b.DestinationType == destinationType);
string[] missingMappings = existingMaps.GetUnmappedPropertyNames();
if (missingMappings.Any())
{
PropertyInfo[] sourceProperties = sourceType.GetProperties();
foreach (string property in missingMappings)
{
foreach (PropertyInfo propertyInfo in sourceProperties)
{
MapToAttribute attr = propertyInfo.GetCustomAttribute<MapToAttribute>();
if (attr != null && attr.Name == property)
{
expression.ForMember(property, opt => opt.ResolveUsing(new MyValueResolve(propertyInfo)));
}
}
}
}
return expression;
}
}
public class MyValueResolve : IValueResolver
{
private readonly PropertyInfo pInfo = null;
public MyValueResolve(PropertyInfo pInfo)
{
this.pInfo = pInfo;
}
public ResolutionResult Resolve(ResolutionResult source)
{
string key = pInfo.GetValue(source.Value) as string;
string value = dictonary[key];
return source.New(value);
}
}
This should be fairly straightforward using an implementation of IValueResolver and the ResolveUsing() method. You basically just need to have a constructor for the resolver that takes in the property info (or if you wanna be fancy that takes in a lambda expression and resolves the property info similar to How to get the PropertyInfo of a specific property?. Though I haven't tested it myself I imagine the following would work:
public class PropertyBasedResolver : IValueResolver
{
public PropertyInfo Property { get; set; }
public PropertyBasedResolver(PropertyInfo property)
{
this.Property = property;
}
public ResolutionResult Resolve(ResolutionResult source)
{
var result = GetValueFromKey(property, source.Value); // gets from some static cache or dictionary elsewhere in your code by reading the prop info and then using that to look up the value based on the key as appropriate
return source.New(result)
}
}
Then to set up that mapping you need to do:
AutoMapper.Mapper.CreateMap<Category, CategoryDto>()
.ForMember(
dest => dest.Value,
opt => opt.ResolveUsing(
src =>
new PropertyBasedResolver(typeof(Category.Key) as PropertyInfo).Resolve(src)));
Of course that is a pretty gross lamda and I would suggest that you clean it up by having your property resolver determine the property on the source object it should look at based on the attribute/property info so you can just pass a clean new PropertyBasedResolver(property) into the ResolveUsing() but hopefully this explains enough to put you on the right track.
Lets assume I have the following classes
public class foo
{
public string Value;
}
public class bar
{
public string Value1;
public string Value2;
}
You can pass a lambda to ResolveUsing:
.ForMember(f => f.Value, o => o.ResolveUsing(b =>
{
if (b.Value1.StartsWith("A"));)
{
return b.Value1;
}
return b.Value2;
}
));
public class Table<T> where T:SomeClassWithIntegerID
{
private Dictionary<int, T> map = new Dictionary<int, T>();
public bool isInMemory(int id)
{
if (map.ContainsKey(id))
return true;
return false;
}
public T setIt(T obj)
{
map[obj.id] = obj;
}
public T getIt(int id)
{
return map[id];
}
}
Example:
private static Table<User> table = new Table<User>;
class User : SomeClassWithIntegerID
{
public string name { get; set; }
public string password { get; set; }
}
class SomeClassWithIntegerID
{
public int id { get; set; }
}
I can now check if the Table holds a user with a certain ID, because I use that as the key, but there is now no way for me to check if the Table holds a User with the name Bob or whatever. I want to be able to do something like table.isInMemory(name, "bob") but how is that possible with a generic type?
I need to create a function that allows the end user to specify the field and expected value of said field, after which Table will go over all objects of that class, stored in the Dictionary, to see if one has the field that matches that value.
Is this possible at all?
public bool IsInMemory(Func<T, bool> predicate)
{
return map.Values.Any(predicate);
}
You can then call it as:
table.IsInMemory(u => u.Name == "bob");
If you want to use a property name and value to match on you could add an overload:
public bool IsInMemory(string propertyName, object value)
{
PropertyInfo property = typeof(T).GetProperty(propertyName);
if(property == null) throw new ArgumentException("Invalid property name: " + propertyName);
var predicate = new Func<T, bool>(item => object.Equals(value, property.GetValue(item, null)));
return IsInMemory(predicate);
}
I would complement Lee's answer with a Where-method to enable querying with LINQ:
public IEnumerable<T> Where(Func<T, bool> predicate)
{
return map.Values.Where(predicate);
}
And an example:
table.Where(x => x.name.Contains("natli"))
.OrderBy(x => x.name);
To answer your actual question, you can (if you're using .NET 4.0) use the dynamic type, which resolves all methods and such at runtime, to call methods or properties that the compiler doesn't know about from its context.
dynamic dynObject = someObject;
dynObject.SomeMethod("Hi there", 27); // Call whatever method or property you "know" exist