Let's say I have this expression:
e => e.Name.StartsWith(GetArgument())
Where GetArgument() is defined as follows:
public string GetArgument() { return "Lu"; }
I want this expression to be translated to the following string:
"begins_with(Name, Lu)"
I have developed an expression visitor that visits each sub expression in a recursive manner:
public class MyExpressionTranslator : ExpressionVisitor, IExpressionTranslator<string>
{
// ....
//Implementing IExpressionTranslator<string>
public string Translate(Expression expr)
{
//Begin visiting the expression and its sub expressions
base.Visit(expr);
// I need to return the string here
return null;
}
// Overrides method from base class ExpressionVisitor
protected override MethodCallExpression VisitMethodCall(MethodCallExpression expr)
{
//This method is called when a method call sub expression is visited
//For example, I can check if the method being called is "StartsWith"
if(expr.Method.Name == "StartsWith")
{
// I have no idea what to do here
}
//Proceeds to visit this expression's sub expressions
return base.VisitMethodCall(expr);
}
}
I would use this class as follows:
MyExpressionTranslator translator = // new MyExpressionTranslator(...)
Expression<Func<SomeClass, bool>> expr = e => e.Name.StartsWith(GetArgument());
string result = translator.Translate(expr);
// result should be "begins_with(Name, Lu)"
Providing my base class has a virtual visit method for each expression type (be it a constant, an argument, a method call, or any other), how can I build the expected string output?
What are you trying to accomplish? Something like the below might work. It won't be easy to fill out the other methods though.
class Program
{
static void Main(string[] args)
{
Expression<Func<TestObject, bool>> expr = e => e.FirstName.StartsWith(GetArgument());
var visitor = new MyExpressionTranslator();
var translation = visitor.Translate(expr); // = "begins_with(FirstName, Lu)"
}
static string GetArgument()
{
return "Lu";
}
}
class TestObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IExpressionTranslator<T>
{
T Translate(Expression expr);
}
public class MyExpressionTranslator : ExpressionVisitor, IExpressionTranslator<string>
{
private StringBuilder _sb = null;
public string Translate(Expression expr)
{
_sb = new StringBuilder();
base.Visit(expr);
// I need to return the string here
return _sb.ToString();
}
protected override Expression VisitMethodCall(MethodCallExpression expr)
{
if (expr.Method.Name == "StartsWith")
{
var mainArg = expr.Arguments[0];
var lambda = Expression.Lambda<Func<string>>(mainArg);
var arg = lambda.Compile()();
var member = expr.Object as MemberExpression;
if (member != null)
{
_sb.AppendFormat("begins_with({0}, {1})", member.Member.Name, arg);
}
else
{
//Don't know what you want here.
_sb.AppendFormat("begins_with({0}, {1}))", "(obj)", arg);
}
}
return base.VisitMethodCall(expr);
}
}
Related
I want to remove any cast expression in an expression tree. We can assume that the cast is redundant.
For example, both these expressions:
IFoo t => ((t as Foo).Bar as IExtraBar).Baz;
IFoo t => ((IExtraBar)(t as Foo).Bar).Baz;
become this:
IFoo t => t.Bar.Baz
How can you accomplish this?
Sample code
The sample below illustrates a pretty simple scenario. However, my coded fails with an exception:
Unhandled Exception: System.ArgumentException: Property 'IBar Bar' is not defined for type 'ExpressionTest.Program+IFoo'
using System;
using System.Linq.Expressions;
namespace ExpressionTest
{
class Program
{
public interface IBar
{
string Baz { get; }
}
public interface IExtraBar : IBar
{
}
public interface IFoo
{
IBar Bar { get; }
}
public class Foo : IFoo
{
public IBar Bar { get; }
}
static void Main(string[] args)
{
Expression<Func<IFoo, string>> expr = t => ((t as Foo).Bar as IExtraBar).Baz;
Expression<Func<IFoo, string>> expr2 = t => ((IExtraBar)(t as Foo).Bar).Baz;
// Wanted: IFoo t => t.Bar.Baz
var visitor = new CastRemoverVisitor();
visitor.Visit(expr);
Console.WriteLine(visitor.Expression.ToString());
}
public class CastRemoverVisitor : ExpressionVisitor
{
public Expression Expression { get; private set; }
public override Expression Visit(Expression node)
{
Expression ??= node;
return base.Visit(node);
}
protected override Expression VisitUnary(UnaryExpression node)
{
Expression = node.Operand;
return Visit(node.Operand);
}
}
}
}
Final solution
The accepted answer pinpoints the use of Expression.MakeMemberAccess and some interface tricks. We can "improve" the code a bit, to use an interfaced PropertyInfo instead of going through the interfaced getter. I ended up with the following:
public class CastRemoverVisitor : ExpressionVisitor
{
protected override Expression VisitUnary(UnaryExpression node)
{
return node.IsCastExpression() ? Visit(node.Operand) : base.VisitUnary(node);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression is UnaryExpression unaryExpression &&
unaryExpression.IsCastExpression())
{
var propertyInfo = node.Member.ToInterfacedProperty();
if (propertyInfo != null)
{
return base.Visit(
Expression.MakeMemberAccess(
unaryExpression.Operand,
propertyInfo
));
}
}
return base.VisitMember(node);
}
}
// And some useful extension methods...
public static class MemberInfoExtensions
{
public static MemberInfo ToInterfacedProperty(this MemberInfo member)
{
var interfaces = member.DeclaringType!.GetInterfaces();
var mi = interfaces.Select(i => i.GetProperty(member.Name))
.FirstOrDefault(p => p != null);
return mi;
}
}
public static class ExpressionExtensions
{
public static bool IsCastExpression(this Expression expression) =>
expression.NodeType == ExpressionType.TypeAs ||
expression.NodeType == ExpressionType.Convert;
}
And then we use it like this:
var visitor = new CastRemoverVisitor();
var cleanExpr = visitor.Visit(expr);
Console.WriteLine(cleanExpr.ToString());
First off, nice repro. Thank you.
The problem is that the property access (t as Foo).Bar is calling the getter for Foo.Bar, and not the getter for IFoo.Bar (yes, those are different things with different MethodInfos).
You can see this by overriding VisitMember and see the MethodInfo being passed.
However, an approach like this seems to work. We have to unwrap things at the point of the member access, since we can only proceed if we can find an equivalent member to access on the uncasted type:
public class CastRemoverVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression is UnaryExpression { NodeType: ExpressionType.TypeAs or ExpressionType.Convert, Operand: var operand } &&
node.Member is PropertyInfo propertyInfo &&
operand.Type.IsInterface)
{
// Is this just inheriting a type from a base interface?
// Get rid of the cast, and just call the property on the uncasted member
if (propertyInfo.DeclaringType == operand.Type)
{
return base.Visit(Expression.MakeMemberAccess(operand, propertyInfo));
}
// Is node.Expression a concrete type, which implements this interface method?
var methodInfo = GetInterfaceMethodInfo(operand.Type, node.Expression.Type, propertyInfo.GetMethod);
if (methodInfo != null)
{
return base.Visit(Expression.Call(operand, methodInfo));
}
}
return base.VisitMember(node);
}
private static MethodInfo GetInterfaceMethodInfo(Type interfaceType, Type implementationType, MethodInfo implementationMethodInfo)
{
if (!implementationType.IsClass)
return null;
var map = implementationType.GetInterfaceMap(interfaceType);
for (int i = 0; i < map.InterfaceMethods.Length; i++)
{
if (map.TargetMethods[i] == implementationMethodInfo)
{
return map.InterfaceMethods[i];
}
}
return null;
}
}
I'm sure there cases which will break this (fields come to mind, and I know GetInterfaceMap doesn't play well with generics in some situations), but it's a starting point.
Is it possible to evaluate a select projection at some point to get a list of which properties are being selected?
For example, if I have the following class:
public class Example()
{
public string Aaa { get; set; }
public int Bbb { get; set; }
public string Ccc { get; set; }
}
and the following select projection:
Expression<Func<Example, Example>> select = x => new Example { Aaa= x.Aaa, Ccc = x.Ccc };
Would it be possible to interpret the select projection to get a result along the lines of var result = new List<string> { "Aaa", "Ccc" };?
The best way to do something like this is using an ExpressionVisitor.
Here is an example:
public class MyMemberExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType == MemberTypes.Property // is a property
&& node.Expression.NodeType == ExpressionType.Parameter // is from a parameter expression
&& Members.All(s => s != node.Member.Name)) // avoids duplicates
{
Members.Add(node.Member.Name);
}
return base.VisitMember(node);
}
public List<string> Members { get; set; } = new List<string>();
}
Then you can use it like this:
// Complex expressions work too!
Example outsideExample = new Example();
Expression<Func<Example, Example>> expression = x => new Example(
x.Aaa + outsideExample.Bbb,
x.Ccc + x.Aaa.Length);
var myVisitor = new MemberExpressionVisitor();
myVisitor.Visit(expression);
Console.WriteLine(string.Join(", ", myVisitor.Members)); // This should print out "Aaa, Ccc"
You can visit How to: Implement an Expression Tree Visitor to learn more on how to implement one.
To find all of the property expressions within that expression you can use an ExpressionVisitor to inspect all of the Expression instances within a given expression and see which are property accesses, and what property is being accessed:
internal class PropertySearchVisitor : ExpressionVisitor
{
private List<MemberInfo> properties = new List<MemberInfo>();
public IEnumerable<MemberInfo> Properties => properties;
protected override Expression VisitMember(MemberExpression node)
{
if (node?.Member?.MemberType == MemberTypes.Property)
properties.Add(node.Member);
return base.VisitMember(node);
}
}
Once you have that you can write a method to visit a given expression and return the properties (or property names) of that expression:
public static IEnumerable<MemberInfo> GetProperties(this Expression expression)
{
var visitor = new PropertySearchVisitor();
visitor.Visit(expression);
return visitor.Properties;
}
public static IEnumerable<string> GetPropertyNames(this Expression expression)
{
var visitor = new PropertySearchVisitor();
visitor.Visit(expression);
return visitor.Properties.Select(property => property.Name);
}
I've built up a simple ArgumentValidator class in order to simplify argument preconditions in any given method. Most of them are null or bounds checks and it gets pretty tedious after a couple of
if (arg == null ) throw new ArgumentNullException(nameof(arg));
So I've come up with the following set up:
public static class ArgumentValidator
{
public interface IArgument<T>
{
string ParamName { get; }
T Value { get; }
}
private class Argument<T>: IArgument<T>
{
public Argument(T argument, string paramName)
{
ParamName = paramName;
Value = argument;
}
public string ParamName { get; }
public T Value { get; }
}
public static IArgument<T> Validate<T>(this T argument, string paramName = null)
{
return new Argument<T>(argument, paramName ?? string.Empty);
}
public static IArgument<T> IsNotNull<T>(this IArgument<T> o)
{
if (ReferenceEquals(o.Value, null))
throw new ArgumentNullException(o.ParamName);
return o;
}
public static IArgument<T> IsSmallerThan<T, Q>(this IArgument<T> o, Q upperBound) where T : IComparable<Q> { ... }
//etc.
}
And I can use it in the following way:
public Bar Foo(object flob)
{
flob.Validate(nameof(flob)).IsNotNull().IsSmallerThan(flob.MaxValue);
}
Ideally I'd love to get rid of nameof(flob) in the Validate call and ultimately get rid of Validate alltogether; the only purpose of Validate is to avoid having to pass nameof(...) on every check down the chain.
Is there a way to get the name flob inside the Validate() method?
Doing that with an extension method is not that easy. It is easier with a static method that takes an LINQ expression (derived from devdigital's answer here):
public static T Validate<T>(this Expression<Func<T>> argument)
{
var lambda = (LambdaExpression)argument;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
string name = memberExpression.Member.Name;
Delegate d = lambda.Compile();
return (T)d.DynamicInvoke();
}
The name inside is the name of the property you put in the method:
MyMethods.Validate(() => o);
Since the Validate returns T, you can use that further on. This might not be as performing as you want it to be, but this is the only viable option.
It is possible to make this an extension method too, you have to create the expression yourself by hand:
Expression<Func<object>> f = () => o; // replace 'object' with your own type
f.Validate();
I have an Expression in the following form:
Expression<Func<T, bool>> predicate = t => t.Value == "SomeValue";
Is it possible to create a 'partially applied' version of this expression:
Expression<Func<bool>> predicate = () => t.Value == "SomeValue";
NB This expression is never actually compiled or invoked, it is merely inspected to generate some SQL.
This could be easily achieved by writing a custom ExpressionVisitor and replacing the parameter with a constant expression that you have captured in a closure:
public class Foo
{
public string Value { get; set; }
}
public class ReplaceVisitor<T> : ExpressionVisitor
{
private readonly T _instance;
public ReplaceVisitor(T instance)
{
_instance = instance;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return Expression.Constant(_instance);
}
}
class Program
{
static void Main()
{
Expression<Func<Foo, bool>> predicate = t => t.Value == "SomeValue";
var foo = new Foo { Value = "SomeValue" };
Expression<Func<bool>> result = Convert(predicate, foo);
Console.WriteLine(result.Compile()());
}
static Expression<Func<bool>> Convert<T>(Expression<Func<T, bool>> expression, T instance)
{
return Expression.Lambda<Func<bool>>(
new ReplaceVisitor<T>(instance).Visit(expression.Body)
);
}
}
I think this should work:
Expression predicate2 = Expression.Invoke(predicate, Expression.Constant(new T() { Value = "SomeValue"}));
Expression<Func<bool>> predicate3 = Expression.Lambda<Func<bool>>(predicate2);
Don't know if this is easily parseable to generate SQL however (it works when compiled - I tried).
Looking for a clean way to discover the string name of a method in a type safe way.
Here is what I have for properties, but I'm having trouble figuring out how to do it for methods.
class Program
{
class Customer
{
public String Id { get; set; }
}
public static String GetPropertyName<T>(
Expression<Func<T, Object>> selector) where T : class
{
var expression = (MemberExpression)selector.Body;
return expression.Member.Name;
}
static void Main(string[] args)
{
String propertyName = GetPropertyName<Customer>(c => c.Id);
}
}
Pretty much by changing to:
var expression = (MethodCallExpression)selector.Body;
return expression.Method.Name;
with the notable exception that you will need an Action<T> option to handle void methods. You will have to supply dummy parameter values, of course - if you really want you can obtain those too.
Actually, your existing code might not be robust; you may need to throw away a cast operation (to box the int to an object).
public static string GetMethodName<T>(Expression<Func<T, Object>> selector) where T : class
{
var expression = (MethodCallExpression)(selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body);
return expression.Method.Name;
}
public static string GetMethodName<T>(Expression<Action<T>> selector) where T : class
{
var expression = (MethodCallExpression)(selector.Body is UnaryExpression ? ((UnaryExpression)selector.Body).Operand : selector.Body);
return expression.Method.Name;
}
If it helps, our code base uses the following:
public class TypeHelper
{
private static PropertyInfo GetPropertyInternal(LambdaExpression p)
{
MemberExpression memberExpression;
if (p.Body is UnaryExpression)
{
UnaryExpression ue = (UnaryExpression)p.Body;
memberExpression = (MemberExpression)ue.Operand;
}
else
{
memberExpression = (MemberExpression)p.Body;
}
return (PropertyInfo)(memberExpression).Member;
}
public static string GetPropertyName<TObject>(Expression<Func<TObject, object>> p)
{
return GetPropertyNameInternal(p);
}
public static string GetPropertyName<TObject, T>(Expression<Func<TObject, T>> p)
{
return GetPropertyNameInternal(p);
}
public static string GetPropertyName<T>(Expression<Func<T>> p)
{
return GetPropertyNameInternal(p);
}
public static string GetPropertyName(Expression p)
{
return GetPropertyNameInternal((LambdaExpression) p);
}
private static string GetPropertyNameInternal(LambdaExpression p)
{
return GetPropertyInternal(p).Name;
}
public static PropertyInfo GetProperty<TObject>(Expression<Func<TObject, object>> p)
{
return GetPropertyInternal(p);
}
public static PropertyInfo GetProperty<TObject, T>(Expression<Func<TObject, T>> p)
{
return GetPropertyInternal(p);
}
public static PropertyInfo GetProperty<T>(Expression<Func<T>> p)
{
return GetPropertyInternal(p);
}
}
That gives you the ability to do:
var propertyName = TypeHelper.GetPropertyName<Customer>(c => c.Id);
Or
var propertyName = TypeHelper.GetPropertyName(() => this.Id); // If inside Customer class
If you happen to have System.Web.Mvc, you can use ExpressionHelper.GetExpressionText(expression), like so:
Expression<Func<Response, string>> expression = r => r.Message;
Assert.AreEqual("Message", ExpressionHelper.GetExpressionText(expression));
(Response being a custom class with a Message property.)