Open delegate to IFormattable.ToString method in struct (Int32, DateTime) - c#

I want to create an open delegate to the method ToString(string, IFormatprovider) of a struct (Int32, DateTime, whatever):
public delegate string MyCoverter(ref DateTime from, string format, IFormatProvider provider);
...
var method = typeof(DateTime).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider)}); // Works!
var d= Delegate.CreateDelegate(typeof(MyCoverter), null, method); // Exception!
It keeps throwing the ArgumentException with message "Error binding to target method.".
I've read almost all stackoverflow articles on this subject, I have experimented with and without ref, I have added and removed the null when creating the delegate. Nothing seems to help.
Has anyone any clue?
* EDIT *
When I create my own struct with the same method, the code above (with DateTime replaced my MyStruct) works perfectly fine.
public struct MyStruct
{
public string ToString(string format, IFormatProvider provider)
{
return null;
}
}
What makes an Int32 or DateTime so different?
* EDIT *
As requested I added a complete "working" program. What I forgot to mention: I am working on .NET framework 3.5. Furthermore, as I stated before, this is all working on MyStruct. Except, when I implement the interface IFormattable, it also does not work anymore.
using System;
namespace OpenDelegates
{
public delegate string MyCoverter<T>(ref T from, string format, IFormatProvider provider)
where T : struct;
class Program
{
static void Main(string[] args)
{
var method = typeof(MyStruct).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider) });
var d = Delegate.CreateDelegate(typeof(MyCoverter<MyStruct>), null, method);
method = typeof(DateTime).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider) });
d = Delegate.CreateDelegate(typeof(MyCoverter<DateTime>), null, method);
}
}
public struct MyStruct //: IFormattable
{
public string ToString(string format, IFormatProvider provider)
{
return null;
}
}
}
* EDIT *
It all works perfectly on .NET Framework 4.x, but that is NOT a solution for me.

I don't know the answer for that specific problem but maybe you can build your own delegate:
public static Func<object, string, IFormatProvider, string> CreateConverter<T>()
where T : struct // not really needed
{
var method = typeof(T).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider) });
if (method == null)
{
throw new InvalidOperationException(string.Format("The type {0} does not contain a suitable ToString-method.", typeof(T).FullName));
}
var instanceParameter = Expression.Parameter(typeof(object), "instance");
var formatParameter = Expression.Parameter(typeof(string), "format");
var providerParameter = Expression.Parameter(typeof(IFormatProvider), "provider");
var convertedInstance = Expression.Convert(instanceParameter, typeof(T));
var methodCall = Expression.Call(convertedInstance, method, formatParameter, providerParameter);
var lambda = Expression.Lambda<Func<object, string, IFormatProvider, string>>(methodCall, instanceParameter, formatParameter, providerParameter);
return lambda.Compile();
}
Can be used like:
var d = CreateConverter<MyStruct>();
Console.WriteLine(d(new MyStruct(), "", CultureInfo.CurrentCulture));
d = CreateConverter<DateTime>();
Console.WriteLine(d(DateTime.Now, "yyyydd", CultureInfo.CurrentCulture));
EDIT to make sure that the input is of the correct type
public static Func<T, string, IFormatProvider, string> CreateConverter<T>()
{
var method = typeof(T).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string), typeof(IFormatProvider) }, null);
if (method == null)
{
throw new InvalidOperationException(string.Format("The type {0} does not contain a suitable ToString-method.", typeof(T).FullName));
}
var instanceParameter = Expression.Parameter(typeof(T), "instance");
var formatParameter = Expression.Parameter(typeof(string), "format");
var providerParameter = Expression.Parameter(typeof(IFormatProvider), "provider");
var methodCall = Expression.Call(instanceParameter, method, formatParameter, providerParameter);
var lambda = Expression.Lambda<Func<T, string, IFormatProvider, string>>(methodCall, instanceParameter, formatParameter, providerParameter);
return lambda.Compile();
}

Related

C# - Faster way to get set public static fields instead of using Reflection.SetValue / GetValue

I have a scenario where I need to change public static fields during runtime. I understand that I can do it through reflection as below to get set the public static field I want, but it is really slow.
string typeName = "ABC";
string fieldName = "IsA";
Type.GetType(typeName ).GetField(fieldName ).SetValue(null, value);
var value = Type.GetType(typeName ).GetField(fieldName ).GetValue(null);
I would like to know is there any faster way to access such as using Reflection.Emit, Linq.Expression or other methods. As what I know currently most of them only support fields with an instance.
You can use expressions for this. You basically have three options:
Reflection. Slow.
Dynamic compiled expression. Fast.
Typed compiled expression. Super fast.
In your case it's a bit tricky to go for typed expressions. I guess we cannot assume that all static properties will be of type string? The second option allows you to easily create a fast setter for any field type.
Note that when compiling expressions, you must maintain a cache for the compiled delegates. The compilation step is very expensive!
UPDATE: Using typed compiled expressions
class Program
{
public class Foo
{
public static string Name;
}
public static void Main()
{
var delegateCache = new Dictionary<(string, string), Action<string>>();
var typeName = typeof(Foo).FullName;
var fieldName = "Name";
var key = (typeName, fieldName);
// Caching is crucial!
if (!delegateCache.TryGetValue(key, out var d))
{
d = CreateStaticSetter(typeName, fieldName);
delegateCache.Add(key, d);
}
d.Invoke("new value");
Console.WriteLine(Foo.Name);
}
private static Action<string> CreateStaticSetter(string typeName, string fieldName)
{
var type = Type.GetType(typeName) ?? throw new ArgumentException();
var field = type.GetField(fieldName) ?? throw new ArgumentException();
var valueExp = Expression.Parameter(field.FieldType, "value");
var fieldExp = Expression.Field(null, field);
var assignExp = Expression.Assign(fieldExp, valueExp);
var expr = Expression.Lambda<Action<string>>(assignExp, valueExp);
return expr.Compile();
}
}
Using dynamic compiled expressions
class Program
{
public class Foo
{
public static string Name;
}
public static void Main()
{
var delegateCache = new Dictionary<(string, string), Delegate>();
var typeName = typeof(Foo).FullName;
var fieldName = "Name";
var key = (typeName, fieldName);
// Caching is crucial!
if (!delegateCache.TryGetValue(key, out var d))
{
d = CreateStaticSetter(typeName, fieldName);
delegateCache.Add(key, d);
}
// For a strongly typed delegate, we would use Invoke() instead.
d.DynamicInvoke("new value");
Console.WriteLine(Foo.Name);
}
private static Delegate CreateStaticSetter(string typeName, string fieldName)
{
var type = Type.GetType(typeName) ?? throw new ArgumentException();
var field = type.GetField(fieldName) ?? throw new ArgumentException();
var valueExp = Expression.Parameter(field.FieldType, "value");
var fieldExp = Expression.Field(null, field);
var assignExp = Expression.Assign(fieldExp, valueExp);
// TODO: Can be further optimized with a strongly typed delegate.
var expr = Expression.Lambda(assignExp, valueExp);
return expr.Compile();
}
}

Open instance delegate with unknown target type?

So I'm trying to create an open delegate that doesn't know the type of its target in advance. I am not sure if that explains it correctly, let me show you:
class X
{
public bool test() { return false; }
}
static void Main()
{
var x = new X();
var runtimeType = x.GetType();
var method = runtimeType.GetMethod("test");
var del = ... INSERT CODE
Console.WriteLine(del(x)); // should output False
}
While Delegate.CreateDelegate(typeof(Func<X, bool>), method); works, but I don't know the type of X at compile time. What I'd like to do, is use typeof(Func<object, bool>) but that's not possible.
I searched and found this article.
I cleaned up some of the code - here's the related bit for me:
public static class MethodInfoExtensions
{
public static Func<TArg0, TReturn> F0<T, TArg0, TReturn>(MethodInfo method)
where T : TArg0
{
var d = (Func<T, TReturn>)Delegate.CreateDelegate(typeof(Func<T, TReturn>), method);
return delegate(TArg0 target) { return d((T)target); };
}
public static T DelegateForCallMethod<T>(this MethodInfo targetMethod)
{
//string creatorName = (targetMethod.ReturnType == typeof(void) ? "A" : "F") + targetMethod.GetParameters().Length.ToString();
// this will just do in my case
string creatorName = "F0";
var methodParams = targetMethod.GetParameters();
var typeGenArgs = typeof(T).GetGenericArguments();
var signature = new Type[1 + methodParams.Length + typeGenArgs.Length];
int idx = 0;
signature[idx++] = targetMethod.DeclaringType;
for (int i = 0; i < methodParams.Length; i++)
signature[idx++] = methodParams[i].ParameterType;
for (int i = 0; i < typeGenArgs.Length; i++)
signature[idx++] = typeGenArgs[i];
var mth = typeof(MethodInfoExtensions).GetMethod(creatorName, BindingFlags.NonPublic | BindingFlags.Static);
var gen = mth.MakeGenericMethod(signature);
var res = gen.Invoke(null, new object[] { targetMethod });
return (T)res;
}
}
Now I can write (in INSERT CODE area) method.DelegateForCallMethod<Func<object, bool>>(); and when I call del(x) it would execute x.test() and output False correctly!
The problem is, changing X to be a struct (which is my actual use-case) breaks it! :(
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has
been thrown by the target of an invocation. ---> System.ArgumentException: Error
binding to target method. at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throw
OnBindFailure) at Vexe.Runtime.Extensions.VexeTypeExtensions.F0[T,TArg0,TReturn](MethodInfo method) in c:\Users\vexe\Desktop\MyExtensionsAndHelpers\Source\Runtime\RuntimeExtensions\TypeExtensions.cs:line 24
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] argum
ents, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle
typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisib
ilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invoke
Attr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at Vexe.Runtime.Extensions.VexeTypeExtensions.DelegateForCallMethod[T](Method
Info targetMethod) in c:\Users\vexe\Desktop\MyExtensionsAndHelpers\Source\Runtime\RuntimeExtensions\TypeExtensions.cs:line 50
at Program.Main(String[] args) in c:\Users\vexe\Desktop\MyExtensionsAndHelpers\Solution\Test\Program2.cs:line 225
(the line is res = ...)
Any idea why this happens? and how to fix it?
Thanks!
Edit: I do not want to use MethodInfo.Invoke. The whole point here is to create a delegate that's much faster to invoke than regular reflection.
Edit: Tracking down the problem, it seems that F0 is failing to create the delegate if X is a struct - It can be verified by calling MethodInfoExtensions.F0<X, object, bool>(method); - if X was a class then no problem!
Edit: Simplified even more, it seems that Delegate.CreateDelegate(typeof(Func<X, bool>), method) fails to bind if X is struct!
Edit: Found this - pretty much the same issue. But the solution implies having a custom delegate with the argument type (in my case X) known at compile time :(
So the problem is that Delegate.CreateDelegate(typeof(Func<X, bool>), method) fails if X is a struct - according to this I should create my own delegate and pass by ref. I did that, it worked, but now it doesn't if I change back to class! It starts working again for class but not struct if I remove the ref!
So given this startup code:
class X
{
public bool test() { return false; }
}
var x = new X();
var runtimeType = x.GetType();
var method = runtimeType.GetMethod("test");
Case1 (works if X is class)
delegate TReturn MyDelegate1<TArg0, TReturn>(TArg0 obj);
var del = Delegate.CreateDelegate(typeof(MyDelegate1<X, bool>), method) as MyDelegate1<X, bool>;
Console.WriteLine(del(x));
Case2 (works if X is struct)
delegate TReturn MyDelegate2<TArg0, TReturn>(ref TArg0 obj);
var del = Delegate.CreateDelegate(typeof(MyDelegate2<X, bool>), method) as MyDelegate2<X, bool>;
Console.WriteLine(del(ref x));
Now in order to adapt the original code with this, I have to have two versions for the delegates: one with ref, another without. And inside the DelegateForCallMethod function, I see if the DeclaringType for the input method is a struct or class, and use the appropriate delegate type accordingly (which I'm not even sure if it'll work)
Might update to add code if it works.
Appreciate it if someone can explain what's going on.
Edit: Here we go - (definitely not the prettiest - I feel like I'm doing something redundant):
public delegate TReturn MethodInvoker<TArg0, TReturn>(TArg0 target);
public delegate TReturn MethodInvokerRef<TArg0, TReturn>(ref TArg0 target);
public static MethodInvoker<TArg0, TReturn> F0Class<T, TArg0, TReturn>(MethodInfo method)
where T : TArg0
{
var d = Delegate.CreateDelegate(typeof(MethodInvoker<T, TReturn>), method) as MethodInvoker<T, TReturn>;
return delegate(TArg0 target)
{
return d((T)target);
};
}
public static MethodInvokerRef<TArg0, TReturn> F0Struct<T, TArg0, TReturn>(MethodInfo method)
where T : TArg0
{
var d = Delegate.CreateDelegate(typeof(MethodInvokerRef<T, TReturn>), method) as MethodInvokerRef<T, TReturn>;
return delegate(ref TArg0 target)
{
var typed = (T)target;
return d(ref typed);
};
}
public static Func<TArg0, TReturn> DelegateForCallMethod<TArg0, TReturn>(this MethodInfo targetMethod)
{
var declType = targetMethod.DeclaringType;
var signature = new Type[3]
{
declType,
typeof(TArg0),
typeof(TReturn)
};
bool isValueType = declType.IsValueType;
string delegateCreator;
if (isValueType)
delegateCreator = "F0Struct";
else
delegateCreator = "F0Class";
var mth = typeof(VexeTypeExtensions).GetMethod(delegateCreator, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
var gen = mth.MakeGenericMethod(signature);
var res = gen.Invoke(null, new object[] { targetMethod });
if (isValueType)
{
var mir = (MethodInvokerRef<TArg, TReturn>)res;
return x => mir(ref x);
}
var mi = (MethodInvoker<TArg, TReturn>)res;
return x => mi(x);
}
Usage:
var x = // ... usual startup code
var del = method.DelegateForCallMethod<object, bool>();
Console.WriteLine(del(x));
in this line:
var mth = typeof(MethodInfoExtensions).GetMethod(creatorName, BindingFlags.NonPublic | BindingFlags.Static);
make the flags appropriate for your method
I'm using similar code to create getter and setter of unknown instance type.
It uses MakeGenericType instead of MakeGenericMethod, which allows to get rid of GetMethod and Invoke in favor of Activator.CreateInstance.
using System;
using System.Reflection;
public static class GetterSetterHelper
{
abstract class Factory<T, TValue>
{
public abstract Func<T, TValue> CreateGetter(MethodInfo method);
public abstract Action<T, TValue> CreateSetter(MethodInfo method);
public static Factory<T, TValue> Create(Type runtimeType)
{
var genericType = runtimeType.IsValueType ? typeof(StructFactory<,,>) : typeof(Factory<,,>);
var factoryType = genericType.MakeGenericType(new Type[] { runtimeType, typeof(T), typeof(TValue) });
return (Factory<T, TValue>)Activator.CreateInstance(factoryType);
}
}
class Factory<TRuntime, T, TValue> : Factory<T, TValue>
where TRuntime : class, T
{
public override Func<T, TValue> CreateGetter(MethodInfo method)
{
var d = (Func<TRuntime, TValue>)Delegate.CreateDelegate(typeof(Func<TRuntime, TValue>), method);
return delegate (T target) { return d((TRuntime)target); };
}
public override Action<T, TValue> CreateSetter(MethodInfo method)
{
var d = (Action<TRuntime, TValue>)Delegate.CreateDelegate(typeof(Action<TRuntime, TValue>), method);
return delegate (T target, TValue value) { d((TRuntime)target, value); };
}
}
class StructFactory<TRuntime, T, TValue> : Factory<T, TValue>
where TRuntime : struct, T
{
delegate TValue GetterDelegate(ref TRuntime instance);
public override Func<T, TValue> CreateGetter(MethodInfo method)
{
var d = (GetterDelegate)Delegate.CreateDelegate(typeof(GetterDelegate), method);
return delegate (T target)
{
var inst = (TRuntime)target;
return d(ref inst);
};
}
public override Action<T, TValue> CreateSetter(MethodInfo method)
{
// It makes little sense to create setter which sets value to COPY of value type
// It would make sense if we use delegate like:
// void ActionRef<T, TValue(ref T inst, TValue value);
throw new NotSupportedException();
}
}
public static Func<T, TValue> CreateGetter<T, TValue>(this MethodInfo methodInfo)
{
return Factory<T, TValue>.Create(methodInfo.ReflectedType).CreateGetter(methodInfo);
}
public static Action<T, TValue> CreateSetter<T, TValue>(this MethodInfo methodInfo)
{
return Factory<T, TValue>.Create(methodInfo.ReflectedType).CreateSetter(methodInfo);
}
}
Testing code:
using System;
class Program
{
class Test
{
public int DoSomething() { return 1; }
}
struct TestStruct
{
public int DoSomething() { return 2; }
}
static void Main(string[] args)
{
var method = typeof(Test).GetMethod("DoSomething");
var getter = method.CreateGetter<object, int>();
Console.WriteLine(getter(new Test()));
var method2 = typeof(TestStruct).GetMethod("DoSomething");
var getter2 = method2.CreateGetter<object, int>();
Console.WriteLine(getter2(new TestStruct()));
Console.ReadKey();
}
}

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...

How to reflect a Static Public Method with Parameter passed by reference, for example Int32.TryParse

I am trying to write a generic extension method targeting .Net 4.5. I want to test a type to see if TryParse is defined in the class. If yes, invoke the TryParse method at runtime.
Here is my implemenation.
using System;
using System.Linq;
using System.Reflection;
namespace ExtentionMethodPractises
{
static public class ExtensionMethods
{
public static T ParseOrDefault<T>(this T targetType, string source) where T : new()
{
if (targetType.GetType().GetMethods(BindingFlags.Static|BindingFlags.Public).Any(methodInfo => methodInfo.Name == "TryParse"))
{
var result = new T();
var parameterTypes = new Type[] {source.GetType(), targetType.GetType()};
var parameterModifier = new ParameterModifier(2);
parameterModifier[0] = false;
parameterModifier[1] = true;
var tryParseMethod = targetType.GetType().GetMethod("TryParse", parameterTypes, new ParameterModifier[] { parameterModifier});
tryParseMethod.Invoke(null, new object[] {source, result});
return result;
}
return new T();
}
}
}
I tested my extension method with System.UInt16 which has TryParse methods. I got a nullref on the tryParseMethod after reflection.
I implemented a dummy test class ReflectorTarget to test my extension method. I got a null reference too. It seems that the reflector is incapable of search methods has pass-by-reference parameter(s).
namespace ExtentionMethodPractises
{
public class ReflectorTarget
{
public static bool TryParse(string source, out ReflectorTarget output)
{
output = new ReflectorTarget();
return true;
}
public static bool TryParse(string source, bool isReally, out ReflectorTarget output)
{
output = new ReflectorTarget();
return true;
}
}
}
Lastly, I changed my dummy test class implementation as follows. Suddenly, the reflector will pick up the TryParse method at runtime. All I did is change the second parameter from a pass-by-reference parameter to a normal parameter.
namespace ExtentionMethodPractises
{
public class ReflectorTarget
{
public static bool TryParse(string source, ReflectorTarget output)
{
return true;
}
public static bool TryParse(string source, bool isReally, out ReflectorTarget output)
{
output = new ReflectorTarget();
return true;
}
}
}
Question: How do I reflect a method (static/non-static) that has a pass-by-reference parameter in C#? Thank you.
I think you want this:
namespace ExtentionMethodPractises
{
static public class ExtensionMethods
{
public static T ParseOrDefault<T>(this T targetType, string source)
where T : new()
{
if (targetType.GetType()
.GetMethods(BindingFlags.Static|BindingFlags.Public)
.Any(methodInfo => methodInfo.Name == "TryParse"))
{
var result = new T();
var parameterTypes = new Type[] {source.GetType(),
//Key change here
targetType.GetType().MakeByRefType()};
var tryParseMethod = targetType.GetType()
.GetMethod("TryParse", parameterTypes);
tryParseMethod.Invoke(null, new object[] {source, result});
return result;
}
return new T();
}
}
}
see MakeByRefType:
Returns a Type object that represents the current type when passed as a ref parameter (ByRef parameter in Visual Basic).
tryParseMethod.Invoke(null, new object[] {source, result});
Damien got you unblocked on passing the correct type, but you still need to invoke the method correctly. A method that takes a ref argument will update the value in the passed object[], it is not going to modify your result variable. And you are interested in the return value of this method. Also notable is that ParameterModifier is actually ignored for .NET methods. Which collapses your method down to:
public static T ParseOrDefault<T>(this T targetType, string source) where T : new() {
var parameterTypes = new Type[] { source.GetType(), targetType.GetType().MakeByRefType() };
var tryParseMethod = targetType.GetType().GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null);
if (tryParseMethod != null) {
var args = new object[] { source, null };
var retval = (bool)tryParseMethod.Invoke(null, args);
if (retval) return (T)args[1];
}
return new T();
}

Expression to Call a Method on Each Property of a Class

I want to take a class, loop through it's properties, get the property value, and call a method passing that property value in. I think I can get the property values, but what does the lambda expression's body look like? What body is used to call a method on each property?
This is what I have so far...
Action<T> CreateExpression<T>( T obj )
{
foreach( var property in typeof( T ).GetProperties() )
{
Expression value = Expression.Property( Expression.Constant( obj ), property );
var method = Expression.Call( typeof( SomeType ), "SomeMethod", null, value );
}
// What expression body can be used that will call
// all the method expressions for each property?
var body = Expression...
return Expression.Lambda<Action<T>>( body, ... ).Compile();
}
It depends on a few things.
does the method return anything? Expression in 3.5 can't do multiple separate "action" operations (a statement body), but you can cheat if you can do something with a fluent API:
SomeMethod(obj.Prop1).SomeMethod(obj.Prop2).SomeMethod(obj.Prop3);
(perhaps using generics to make it simpler)
do you have access to 4.0? In 4.0 there are additional Expression types allowing statement bodies and exactly what you ask for. I discuss some similar examples in an article here (look for Expression.Block, although this is based on a beta a while ago - it may have been renamed by now).
Alternative; since you are compiling to a delegate, consider that an Action<T> is multicast; you could build a set of simple operations, and combine them in the delegate; this would work in 3.5; for example:
using System;
using System.Linq.Expressions;
static class SomeType
{
static void SomeMethod<T>(T value)
{
Console.WriteLine(value);
}
}
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
static class Program
{
static readonly Action<Customer> action = CreateAction<Customer>();
static void Main()
{
Customer cust = new Customer { Id = 123, Name = "Abc" };
action(cust);
}
static Action<T> CreateAction<T>()
{
Action<T> result = null;
var param = Expression.Parameter(typeof(T), "obj");
foreach (var property in typeof(T).GetProperties(
BindingFlags.Instance | BindingFlags.Public))
{
if (property.GetIndexParameters().Length > 0) continue;
var propVal = Expression.Property(param, property);
var call = Expression.Call(typeof(SomeType), "SomeMethod", new Type[] {propVal.Type}, propVal);
result += Expression.Lambda<Action<T>>(call, param).Compile();
}
return result;
}
}
I dont think it will be so easy using Expressions, in .NET 3.5 at least.
.NET 4 supports a block construct I believe.
I suggest using Reflection.Emit rather.
Here is a starting point (for fields but can be changed easily):
internal static T CreateDelegate<T>(this DynamicMethod dm) where T : class
{
return dm.CreateDelegate(typeof(T)) as T;
}
static Dictionary<Type, Func<object, Dictionary<string, object>>> fieldcache =
new Dictionary<Type, Func<object, Dictionary<string, object>>>();
static Dictionary<string, object> GetFields(object o)
{
var t = o.GetType();
Func<object, Dictionary<string, object>> getter;
if (!fieldcache.TryGetValue(t, out getter))
{
var rettype = typeof(Dictionary<string, object>);
var dm = new DynamicMethod(t.Name + ":GetFields",
rettype, new Type[] { typeof(object) }, t);
var ilgen = dm.GetILGenerator();
var instance = ilgen.DeclareLocal(t);
var dict = ilgen.DeclareLocal(rettype);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Castclass, t);
ilgen.Emit(OpCodes.Stloc, instance);
ilgen.Emit(OpCodes.Newobj, rettype.GetConstructor(Type.EmptyTypes));
ilgen.Emit(OpCodes.Stloc, dict);
var add = rettype.GetMethod("Add");
foreach (var field in t.GetFields(
BindingFlags.DeclaredOnly |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic))
{
if (!field.FieldType.IsSubclassOf(typeof(Component)))
{
continue;
}
ilgen.Emit(OpCodes.Ldloc, dict);
ilgen.Emit(OpCodes.Ldstr, field.Name);
ilgen.Emit(OpCodes.Ldloc, instance);
ilgen.Emit(OpCodes.Ldfld, field);
ilgen.Emit(OpCodes.Castclass, typeof(object));
ilgen.Emit(OpCodes.Callvirt, add);
}
ilgen.Emit(OpCodes.Ldloc, dict);
ilgen.Emit(OpCodes.Ret);
fieldcache[t] = getter = dm.CreateDelegate<Func<object,
Dictionary<string, object>>>();
}
return getter(o);
}
Use the Block statement. The code below for example writes out the names of all properties
static void WritePropertyNames()
{
TestObject lTestObject = new TestObject();
PropertyInfo[] lProperty = typeof(TestObject).GetProperties();
List<Expression> lExpressions = new List<Expression>();
MethodInfo lMethodInfo = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
lProperty.ForEach(x =>
{
ConstantExpression lConstant = Expression.Constant(x.Name);
MethodCallExpression lMethodCall = Expression.Call(lMethodInfo, lConstant);
lExpressions.Add(lMethodCall);
});
BlockExpression lBlock = Expression.Block(lExpressions);
LambdaExpression lLambda = Expression.Lambda<Action>(lBlock, null);
Action lWriteProperties = lLambda.Compile() as Action;
lWriteProperties();
}
Expression trees can only contain a single statement. To do what you are trying you would need to Expression.Lambda<>() in your loop, passing "method" as the body.
I believe this has changed in .NET Framework 4.0.
Andrew
If you're willing to have your method SomeType.SomeMethod accept an object[] then you can do something like this (note that indexers can not be handled here so we discard them):
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Test {
class SomeType {
public static void SomeMethod(object[] values) {
foreach (var value in values) {
Console.WriteLine(value);
}
}
}
class Program {
static Action<T> CreateAction<T>() {
ParameterExpression parameter = Expression.Parameter(
typeof(T),
"parameter"
);
List<Expression> properties = new List<Expression>();
foreach (var info in typeof(T).GetProperties()) {
// can not handle indexers
if(info.GetIndexParameters().Length == 0) {
Expression property = Expression.Property(parameter, info);
properties.Add(Expression.Convert(property, typeof(object)));
}
}
Expression call = Expression.Call(
typeof(SomeType).GetMethod("SomeMethod"),
Expression.NewArrayInit(typeof(object), properties)
);
return Expression.Lambda<Action<T>>(call, parameter).Compile();
}
static void Main(string[] args) {
Customer c = new Customer();
c.Name = "Alice";
c.ID = 1;
CreateAction<Customer>()(c);
}
}
class Customer {
public string Name { get; set; }
public int ID { get; set; }
}
}
Of course this will be easier in .NET 4.0 with the LoopExpression.

Categories