How to call static field method in static class using reflection - c#

I have this static class with Specifications:
public static class OperationSpecs
{
public static ISpecification<TestEntity> TestSpec = new Specification<TestEntity>(
o =>
{
return (o.Param1== 1 &&
o.Param2== 3
);
}
);
Specification implementation:
public class Specification<T> : ISpecification<T>
{
private Func<T, bool> expression;
public Specification(Func<T, bool> expression)
{
if (expression == null)
throw new ArgumentNullException();
else
this.expression = expression;
}
public bool IsSatisfiedBy(T o)
{
return this.expression(o);
}
}
How can I call TestSpec.IsSatisfiedBy(someType) using reflection ? I tried this:
var specAttr = op.GetCustomAttribute<OperationSpecificationAttribute>();
var specType = specAttr.SpecificationType;
var specTypeMethodName = specAttr.SpecificationMethodName;
var specField = specType.GetField(specTypeMethodName, BindingFlags.Public | BindingFlags.Static);
if (specField != null)
{
var specFieldType = specField.FieldType;
var result2 = specField.GetValue(null).GetType().GetMethod("IsSatisfiedBy").Invoke(null, new object[] { entity });
}
I got ERROR when call Invoke Non-static method requires a target ... I need to get boolean result..
Thanks for Help!

You are trying to invoke the method IsSatisfiedBy using reflection. In contradiction to your title, this method is NOT a static method, it is an instance method. You you need to invoke the method WITH it's instance:
var instance = specField.GetValue(null);
var instanceType = instance.GetType();
var methodInfo = instanceType.GetMethod("IsSatisfiedBy");
var result2 = methodInfo.Invoke(instance, new object[] { entity }); // <<-- instance added.
or in short:
var instance = specField.GetValue(null);
var result2 = instance.GetType().GetMethod("IsSatisfiedBy").Invoke(instance, new object[] { entity });

Related

How to Invoke Method<T>(Func<Action<T>> action) with private type

I hope the code snipped illustrates my issue.
I need to Invoke the CallEvent method like it is in the out-commented line.
I have no access to the ThirdParty or AnotherThirdParty class.
This is as far as I come:
public class ThirdParty
{
private struct MsgType
{ }
private static void AnotherFunc(MsgType msg)
{ }
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{ }
}
public class MyClass
{
public static void Main()
{
Type MsgType = typeof(ThirdParty).GetNestedType(
"MsgType", BindingFlags.Instance | BindingFlags.NonPublic);
object msg = Activator.CreateInstance(MsgType);
MethodInfo CallEvent = typeof(AnotherThirdParty).GetMethod("CallEvent");
CallEvent = CallEvent.MakeGenericMethod(MsgType);
MethodInfo AnotherFunc = typeof(ThirdParty).GetMethod(
"AnotherFunc", BindingFlags.Static | BindingFlags.NonPublic);
CallEvent.Invoke(null, new object[] {???, msg});
//CallEvent<MsgType>((int x) => new Action<MsgType>(AnotherFunc), msg);
// I can't get my head around how to solve this (Action<msgtype>)
}
}
I also tried:
CallEvent.Invoke(null, new object[]
{
new Func<int, Action<object>>((int x) =>
new Action<object>((object y) =>
AnotherFunc.Invoke(null, new object[] { y }))),
msg
});
I get the following Exception:
System.ArgumentException: Object of type
'System.Func2[System.Int32,System.Action1[System.Object]]' cannot be
converted to type
'System.Func2[System.Int32,System.Action1[ThirdParty+MsgType]].
How should I proceed?
public class ThirdParty
{
private struct MsgType { }
private static void AnotherFunc(MsgType msg)
{
// Inserted to demonstrate getting here
Console.WriteLine($"HEY: {msg}");
}
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{
// Inserted to demonstrate calling the func and then
// the action
action(12)(arg);
}
}
public static void Main()
{
var msgTypeType =
typeof(ThirdParty).GetNestedType("MsgType", BindingFlags.NonPublic);
// This is the message type we're passing (presumably you'll do more with it)
var ourMsgTypeArg = Activator.CreateInstance(msgTypeType);
// Get the reference to the CallEvent method
var callEventMethod =
typeof(AnotherThirdParty).GetMethod("CallEvent", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(msgTypeType);
// Get the reference to the AnotherFunc method
var anotherFunc =
typeof(ThirdParty).GetMethod("AnotherFunc", BindingFlags.NonPublic | BindingFlags.Static);
// Build the func to pass along to CallEvent
var func = CreateFunc(msgTypeType, anotherFunc);
// Call the CallEvent<MsgType> method.
callEventMethod.Invoke(null, new object[] {
func,
ourMsgTypeArg
});
}
private static Delegate CreateFunc(Type msgType, MethodInfo anotherFunc)
{
// The func takes an int
var intArg = Expression.Parameter(typeof(int));
// The action takes a msgType
var msgTypeArg = Expression.Parameter(msgType);
// Represent the call out to "AnotherFunc"
var call = Expression.Call(null, anotherFunc, msgTypeArg);
// Build the action to just make the call to "AnotherFunc"
var action = Expression.Lambda(call, msgTypeArg);
// Build the func to just return the action
var func = Expression.Lambda(action, intArg);
// Compile the chain and send it out
return func.Compile();
}
This code functions as you've requested and prints the following:
HEY: UserQuery+ThirdParty+MsgType
This seems to run:
MethodInfo miCreateDelegate = typeof(MethodInfo).GetMethod("CreateDelegate", new[] { typeof(Type), typeof(Object) });
var ActionType = typeof(Action<>).MakeGenericType(MsgType);
var lambdabody = Expression.Convert(Expression.Call(Expression.Constant(AnotherFunc), miCreateDelegate, new[] { Expression.Constant(ActionType), Expression.Constant(null) }), ActionType);
var intparm = Expression.Parameter(typeof(int));
var lambda = Expression.Lambda(lambdabody, intparm);
CallEvent.Invoke(null, new object[] {
lambda.Compile(),
msg
});
A more complete answer is how did I generate this? I used LINQPad to compile a simpler, similar expression substituting string for MsgType into an Expression:
public static void afunc(string x) { }
Expression<Func<int, Action<string>>> lambda = (int x) => new Action<string>(afunc);
Then I used the LINQPad Dump() function to output the expression tree.
lambda.Dump();
Then some spelunking in MSDN Expression documentation gave me the right static methods to create the pieces. I already knew how to instantiate generic types from an extension method for LINQPad that creates anonymous types on the fly to extend Dump() to exclude fields from anonymous objects, and I knew how to create lambdas from an extension method that extends LINQ with a proper SQL-translatable Left and Right Join operation.
Use Delegate.CreateDelegate method to construct an Action<MsgType> object. Construct Func<int,Action<T>> using Expression.Lambda<>:
var actionType = typeof(Action<>).MakeGenericType(MsgType);
var funcType = typeof(Func<,>).MakeGenericType(typeof(int), actionType);
var p1 = Expression.Parameter(typeof(int));
var p2 = Expression.Parameter(actionType);
var delegate = Expression.Constant(Delegate.CreateDelegate(actionType, AnotherFunc), funcType);
var lambda = Expression.Lambda(delegate, p1, p2);
CallEvent.Invoke(null, new object[] {
lambda.Compile()
, msg
});
This will work and will print an A but the function factory is a mistery to me so I just returned the created delegate. And this is compatible with .net standard 1.1
static void Main(string[] args)
{
Type MsgType = typeof(ThirdParty).GetNestedType(
"MsgType", BindingFlags.Instance | BindingFlags.NonPublic);
object msg = Activator.CreateInstance(MsgType);
MethodInfo CallEvent = typeof(AnotherThirdParty).GetMethod("CallEvent");
CallEvent = CallEvent.MakeGenericMethod(MsgType);
MethodInfo AnotherFunc = typeof(ThirdParty).GetMethod(
"AnotherFunc", BindingFlags.Static | BindingFlags.NonPublic);
var actionType = typeof(Action<>).MakeGenericType(MsgType);
var actionDelegate = AnotherFunc.CreateDelegate(actionType);
var param = Expression.Parameter(typeof(int));
var funcDelegate = Expression.Lambda(Expression.Constant(actionDelegate),param).Compile();
CallEvent.Invoke(null, new []{ funcDelegate, msg });
Console.ReadLine();
}
public class ThirdParty
{
private struct MsgType
{ }
private static void AnotherFunc(MsgType msg)
{
Console.WriteLine("A");
}
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{
action(1)(arg);
}
}

correct signature to use in getmethod on class with multiple overloaded generic methods requiring delegate argument

Following an answer fulfilling the question in part here is some additional information to hopefully solve the points still at issue
Start edit
var curEntityPI = ctx.GetType().GetProperties().Where(pr => pr.Name == "Client").First();
Type curEntityType = curEntityPI.PropertyType.GetGenericArguments().First();
Type[] typeArgs = { curEntityType };
Type propertyManagerType = generic.MakeGenericType(typeArgs);
var propertyManager = Activator.CreateInstance(propertyManagerType, new object[] {});
with this in mind i can't use the closeMethod.Invoke in the same way displayed in the first answer and it is the Func and return body that I don't know how to put in place when invoking
End edit
What should the method signature look like to reflection, I'm trying to invoke the equivalent of this
DynamicPropertyManager<ThreeColumns>.CreateProperty<ThreeColumns, string>(
"Four",
t => "Four",
null
));
on this class found here http://putridparrot.com/blog/dynamically-extending-an-objects-properties-using-typedescriptor/
But I'm trying to do it using reflection. What I'm struggling with
the most is getting the correct method overload.
I have to be honest though I'm also not totally sure how to supply the correct argument for the lambda bit through reflection
either.
I was going to try this in part but don't know what the func bit
would look like when doing MakeGenericMethod
Func<string> funcArg = () => { return "Four"; };
object[] args = { fieldOrPropertyName , funcArg, null };
The class contents from the link above are included for reference.
public class DynamicPropertyManager<TTarget> : IDisposable
{
private readonly DynamicTypeDescriptionProvider provider;
private readonly TTarget target;
public DynamicPropertyManager()
{
Type type = typeof(TTarget);
provider = new DynamicTypeDescriptionProvider(type);
TypeDescriptor.AddProvider(provider, type);
}
public DynamicPropertyManager(TTarget target)
{
this.target = target;
provider = new DynamicTypeDescriptionProvider(typeof(TTarget));
TypeDescriptor.AddProvider(provider, target);
}
public IList<PropertyDescriptor> Properties
{
get { return provider.Properties; }
}
public void Dispose()
{
if (ReferenceEquals(target, null))
{
TypeDescriptor.RemoveProvider(provider, typeof(TTarget));
}
else
{
TypeDescriptor.RemoveProvider(provider, target);
}
}
public static DynamicPropertyDescriptor<TTargetType, TPropertyType>
CreateProperty<TTargetType, TPropertyType>(
string displayName,
Func<TTargetType, TPropertyType> getter,
Action<TTargetType, TPropertyType> setter,
Attribute[] attributes)
{
return new DynamicPropertyDescriptor<TTargetType, TPropertyType>(
displayName, getter, setter, attributes);
}
public static DynamicPropertyDescriptor<TTargetType, TPropertyType>
CreateProperty1<TTargetType, TPropertyType>(
string displayName,
Func<TTargetType, TPropertyType> getHandler,
Attribute[] attributes)
{
return new DynamicPropertyDescriptor<TTargetType, TPropertyType>(
displayName, getHandler, (t, p) => { }, attributes);
}
public static DynamicPropertyDescriptor<TTargetType, TPropertyType>
CreateProperty<TTargetType, TPropertyType>(
string displayName,
Func<TTargetType, TPropertyType> getHandler,
Attribute[] attributes)
{
return new DynamicPropertyDescriptor<TTargetType, TPropertyType>(
displayName, getHandler, (t, p) => { }, attributes);
}
}
Reflection and generics are working very well together, but how to approach a specific goal is very context dependant, because of possibly closed, open and partially closed types and methods. Nonetheless often it is easy to get what you are looking for by using Linq. Have a look:
// get type from somewhere
var compileTimeUnknownType = Type.GetType("ThreeColumns");
if (compileTimeUnknownType == null)
throw new ArgumentException("compileTimeUnknownType");
var managerType = typeof (DynamicPropertyManager<>).MakeGenericType(compileTimeUnknownType);
var createPropertyMethod = managerType.GetMethods().Single(x =>
{
var p = x.GetParameters();
var g = x.GetGenericArguments();
return x.Name == "CreateProperty" &&
p.Length == 3 &&
g.Length == 2 &&
p[0].ParameterType == typeof (string) &&
p[1].ParameterType == typeof (Func<,>).MakeGenericType(g) &&
p[2].ParameterType == typeof (Attribute[]);
});
var closedMethod = createPropertyMethod.MakeGenericMethod(new[] {compileTimeUnknownType, typeof (string)});
var paramExpr = Expression.Parameter(compileTimeUnknownType, "arg");
var lambda =
Expression.Lambda(typeof (Func<,>).MakeGenericType(new[] {compileTimeUnknownType, typeof (string)}),
Expression.Constant("Four"), new List<ParameterExpression>() {paramExpr}).Compile();
var ret = closedMethod.Invoke(null, new object[] {"Four", lambda, null});

Conditional method calls in an expression tree

I'm trying to add an additional method call to my expression tree, but I'm slightly confused how to implement it. Here is what I'm currently working with:
private static Action<object, object> CreateSetter(SetterInfo info)
{
var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
return (s, v) => { };
var objParameter = Expression.Parameter(typeof(object));
var valueParameter = Expression.Parameter(typeof(object));
//This is the method call I'm trying to add
if (info.Name[0] == 'G' && info.Type.Name == TaxDataConstant.ParcelFeat)
{
var convertParcelFeatCall = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));
}
var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, Expression.Constant(propertyInfo.PropertyType));
var objCast = Expression.Convert(objParameter, info.Type);
var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType);
var property = Expression.Property(objCast, propertyInfo);
var assignment = Expression.Assign(property, valueCast);
var lambda = Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);
return lambda.Compile();
}
What I want to happen is:
1) If the name of the type in my SetterInfo object is ParcelFeat and the Properties name begins with 'G' I want to call ConvertParcelFeat on valueParameter and then call ChangeType on the return.
2) If the name of the type is anything other than ParcelFeat call Changetype as normal with out the additional steps
What I'm confused is how to build the conditional. I'm assuming the way I'm doing it in the above code is wrong and I need to use something like Expression.IfThen() to to build the conditional. I'm also unsure how I can chain the method calls like I want.
You do not need in Expression.IfThen because for each specific SetterInfo you combine exactly one specific lambda instance.
Just plug in convertParcelFeatCall in proper place of your ExpressionTree and all should work just fine.
So your code might look like:
class Program
{
static void Main(string[] args)
{
var program = new Program();
var weightLambda = program.DoInternal("Weight").ToString()
== "(Param_0, Param_1) => (Convert(Param_0).Weight = Convert(ChangeType(Param_1, System.Object)))";
var goodiesLambda = program.DoInternal("Goodies").ToString()
== "(Param_0, Param_1) => (Convert(Param_0).Goodies = Convert(ChangeType(Param_1, ConvertParcelFeat(Param_1, \"Goodies\"))))";
Console.WriteLine("WeightLambda is Ok: {0}\nGoodiesLambda is Ok: {1}", weightLambda, goodiesLambda);
}
public Action<Object, Object> Do(string name)
{
return DoInternal(name).Compile();
}
public Expression<Action<object, object>> DoInternal(string name)
{
var info = new {Name = name, Type = typeof(Program)};
var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var objParameter = Expression.Parameter(typeof(object));
var valueParameter = Expression.Parameter(typeof(object));
//This is the method call I'm trying to add
Expression toBeTypeChanged;
if (info.Name[0] == 'G' && info.Type.Name == "Program")
{
toBeTypeChanged = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));
}
else
{
toBeTypeChanged = Expression.Constant(propertyInfo.PropertyType);
}
var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, toBeTypeChanged);
var objCast = Expression.Convert(objParameter, info.Type);
var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType);
var property = Expression.Property(objCast, propertyInfo);
var assignment = Expression.Assign(property, valueCast);
return Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);
}
public object Weight { get; set; }
public object Goodies { get; set; }
public static object ChangeType(object valueParameter, object constant)
{
return null;
}
public static object ConvertParcelFeat(object valueParameter, object constant)
{
return null;
}
public MethodInfo ConvertParcelFeatMethod
{
get { return typeof(Program).GetMethod("ConvertParcelFeat"); }
}
public MethodInfo ChangeTypeMethod
{
get { return typeof(Program).GetMethod("ChangeType"); }
}
}

How to create a Func<> delegate programmatically

I have a small dependency injection framework, and I am trying to make it resolve Lazy<> instances dynamically. The idea is to do something like that:
DIContainer.Register<IDbCommand,SqlCommand>();
var lazyCommand = DIContainer.Resolve<Lazy<IDbCommand>>();
I read the other day that Autofac was able of doing that.
I am stuck trying to set the constructor for that Lazy<> instance. In the next test code, a exception is thrown because the desired type constructor is expecting a Func<arg>, but I am passing a Func<Object>:
static readonly Type _lazyType = typeof(Lazy<>);
static Object ResolveTest(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == _lazyType)
{
var arg = type.GetGenericArguments()[0];
return Activator.CreateInstance(_lazyType.MakeGenericType(arg), new Func<Object>(() => ResolveType(arg)));
}
else
return ResolveType(type);
}
I am out of ideas about how to create a delegate that fits for the Lazy<> constructor parameter. Any idea?
Cheers.
That's not trivial. One possible solution would be to work with reflection:
Create a generic ResolveType method:
public static T ResolveType<T>()
{
return (T)ResolveType(typeof(T));
}
Create a delegate that uses this method:
// You probably want to cache this MethodInfo:
var method = typeof(TypeContainingResolveType)
.GetMethods()
.Single(x => x.IsGenericMethod &&
x.Name == "ResolveType")
.MakeGenericMethod(arg);
var delegate = Delegate.CreateDelegate(
typeof(Func<>).MakeGenericType(arg),
method);
Use that delegate:
return Activator.CreateInstance(_lazyType.MakeGenericType(arg), delegate);
This app outputs "True" and "0". I.e. ResolveTest(typeof(Lazy<int>)) returns a Lazy<int> object, constructed like you wanted.
using System;
using System.Linq.Expressions;
namespace TestApp
{
public class Class1
{
public static void Main()
{
object lazyInt = ResolveTest(typeof(Lazy<int>));
Console.WriteLine(lazyInt.GetType() == typeof(Lazy<int>));
Console.WriteLine(((Lazy<int>)lazyInt).Value);
}
static readonly Type _lazyType = typeof(Lazy<>);
static Object ResolveTest(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == _lazyType)
{
var arg = type.GetGenericArguments()[0];
var lazyArgType = _lazyType.MakeGenericType(arg);
var funcArgType = typeof(Func<>).MakeGenericType(arg);
var funcCtor = lazyArgType.GetConstructor(new[] { funcArgType });
Expression<Func<object>> f = () => ResolveTest(arg);
var func = typeof(Class1).GetMethod("BuildCastedThing").MakeGenericMethod(arg).Invoke(null, new[] { f });
var arguments = new object[] { func };
var retVal = funcCtor.Invoke(arguments);
return retVal;
}
else
return ResolveType(type);
}
public static object ResolveType(Type type)
{
return Activator.CreateInstance(type);
}
public static Func<T> BuildCastedThing<T>(Expression<Func<object>> f)
{
Expression<Func<T>> expr =
Expression.Lambda<Func<T>>(
Expression.Convert(
Expression.Invoke(f),
typeof(T)));
return expr.Compile();
}
}
}
This is a way to rewrite ResolveTest as a generic Resolve<T> (e.g. Resolve<int> returns Lazy<int>). This is a little different, since there's no equivalent to ResolveTest(typeof(int)), which returns an int.
static Lazy<T> Resolve<T>()
{
var arg = typeof(T);
return new Lazy<T>(() => (T)ResolveType(arg));
}
Or with a generic ResolveType<T>:
static Lazy<T> Resolve<T>()
{
return new Lazy<T>(() => ResolveType<T>());
}
public static T ResolveType<T>()
{
return Activator.CreateInstance<T>();
}
public static Object ResolveTest(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == _lazyType)
{
var arg = type.GetGenericArguments()[0];
Expression<Func<object>> expressionWithFuncOfTypeObject = () => ResolveType(arg);
UnaryExpression expressionThatEvaluatesToAnObjectOfTypeArg = Expression.Convert(expressionWithFuncOfTypeObject.Body, arg);
LambdaExpression expressionWithFuncOfTypeArg = Expression.Lambda(typeof(Func<>).MakeGenericType(arg), expressionThatEvaluatesToAnObjectOfTypeArg);
Delegate funcOfTypeArg = expressionWithFuncOfTypeArg.Compile(); // <-- At runtime this will be of type Func<T>
return Activator.CreateInstance(_lazyType.MakeGenericType(arg), funcOfTypeArg);
}
else
return ResolveType(type);
}

Get the parameter value from a Linq Expression

I have the following class
public class MyClass
{
public bool Delete(Product product)
{
// some code.
}
}
Now I have a helper class that looks like this
public class Helper<T, TResult>
{
public Type Type;
public string Method;
public Type[] ArgTypes;
public object[] ArgValues;
public Helper(Expression<Func<T, TResult>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
this.Type = typeof(T);
this.Method = body.Method.Name;
this.ArgTypes = body.Arguments.Select(x => x.Type).ToArray();
this.ArgValues = ???
}
}
The idea ist to use this code from somewhere:
// I am returning a helper somewhere
public Helper<T> GetMethod<T>()
{
var product = GetProduct(1);
return new Helper<MyClass>(x => x.Delete(product));
}
// some other class decides, when to execute the helper
// Invoker already exists and is responsible for executing the method
// that is the main reason I don't just comile and execute my Expression
public bool ExecuteMethod<T>(Helper<T> helper)
{
var instance = new MyClass();
var Invoker = new Invoker(helper.Type, helper.Method, helper.ArgTypes, helper.ArgValues);
return (bool)Invoker.Invoke(instance);
}
The point where I am stuck is how to extract the arguments from the expression itself.
I found this way
((ConstantExpression)((MemberExpression)body.Arguments[0]).Expression).Value
which seems to be an object type with a field "product" but I believe there must be a simpler solution.
Any suggestions.
Update
Just to clarify, I modified my code according to what I want to achive. In my real word application I already have a class that does the same but without an expression tree:
var helper = new Helper(typeof(MyClass), "Delete",
new Type[] { typeof(Product) }, new object[] {product}));
The main reason for my Helper<T> is to have Compile-Time checking if the method signature is valid.
Update 2
This is my current implementation, is there a better way to acces the values, without using reflection?
public Helper(Expression<Func<T, TResult>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
this.Type = typeof(T);
this.Method = body.Method.Name;
this.ArgTypes = body.Arguments.Select(x => x.Type).ToArray();
var values = new List<object>();
foreach(var arg in body.Arguments)
{
values.Add(
(((ConstantExpression)exp.Expression).Value).GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.Expression).Value);
);
}
this.ArgValues = values.ToArray();
}
This method works pretty well. It returns the argument types and values for an Expression>
private static KeyValuePair<Type, object>[] ResolveArgs<T>(Expression<Func<T, object>> expression)
{
var body = (System.Linq.Expressions.MethodCallExpression)expression.Body;
var values = new List<KeyValuePair<Type, object>>();
foreach (var argument in body.Arguments)
{
var exp = ResolveMemberExpression(argument);
var type = argument.Type;
var value = GetValue(exp);
values.Add(new KeyValuePair<Type, object>(type, value));
}
return values.ToArray();
}
public static MemberExpression ResolveMemberExpression(Expression expression)
{
if (expression is MemberExpression)
{
return (MemberExpression)expression;
}
else if (expression is UnaryExpression)
{
// if casting is involved, Expression is not x => x.FieldName but x => Convert(x.Fieldname)
return (MemberExpression)((UnaryExpression)expression).Operand;
}
else
{
throw new NotSupportedException(expression.ToString());
}
}
private static object GetValue(MemberExpression exp)
{
// expression is ConstantExpression or FieldExpression
if (exp.Expression is ConstantExpression)
{
return (((ConstantExpression)exp.Expression).Value)
.GetType()
.GetField(exp.Member.Name)
.GetValue(((ConstantExpression)exp.Expression).Value);
}
else if (exp.Expression is MemberExpression)
{
return GetValue((MemberExpression)exp.Expression);
}
else
{
throw new NotImplementedException();
}
}
You can compile the argument expression and then invoke it to calculate the value:
var values = new List<object>();
foreach(var arg in body.Arguments)
{
var value = Expression.Lambda(argument).Compile().DynamicInvoke();
values.Add(value);
}
this.ArgValues = values.ToArray();
Here is an example of creation of a delegate using a lambda. The object instance is encapsulated into the delegate using a C# feature called closure.
MyClass instance = new MyClass();
//This following line cannot be changed to var declaration
//since C# can't infer the type.
Func<Product, bool> deleteDelegate = p => instance.Delete(p);
Product product = new Product();
bool deleted = deleteDelegate(product);
Alternatively you are trying to create a Helper that automagically Currys.
public class Helper<T>
where T : new()
{
public TResult Execute<TResult>(Func<T, TResult> methodLambda)
{
var instance = new T();
return methodLamda(instance);
}
}
public void Main()
{
var helper = new Helper<MyClass>();
var product = new Product();
helper.Execute(x => x.Delete(product));
}
However I have to say this problem looks suspiciously like the creation of a Helper class to handle the lifetime of a WCF proxy....You know...just say...in which case this ISN'T how I would approach this...simply because this approach leaks WCF specific code into your domain.

Categories

Resources