Why is Ldvirtftn unverifiable? - c#

Can anyone explain when using an anonymously hosted dynamic method why I get an unverifiable exception by ldvirtftn for a public virtual method on a public class? I set the following assembly level attributes as well:
[assembly: SecurityTransparent]
[assembly: SecurityRules(SecurityRuleSet.Level2,SkipVerificationInFullTrust=true)]
Here is the example code:
public class Program
{
public virtual void Foo() {}
public static void Main(string[] args)
{
Action<ILGenerator> genfunc = il => il
.newobj<Program>()
.ldvirtftn(typeof(Program).GetMethod("Foo"))
.ret();
try
{
Console.WriteLine(CodeGen.CreateDelegate<Func<IntPtr>>(genfunc).Invoke());
}
catch (System.Security.VerificationException) { }
Console.WriteLine(CodeGen.CreateDelegate<Func<IntPtr>>(genfunc,owner:typeof(Program)).Invoke());
}
}
If the method is owned, then it does not throw an exception.
Even more curious is that if I change the code like so then both methods compile and run without issue:
public class Program
{
public virtual void Foo() {}
public static void Main(string[] args)
{
Action<ILGenerator> genfunc = il => il
.newobj<Program>()
.dup()
.ldvirtftn(typeof(Program).GetMethod("Foo"))
.newobj<Action>(typeof(object),typeof(IntPtr))
.ret();
try
{
Console.WriteLine(CodeGen.CreateDelegate<Func<Action>>(genfunc).Invoke());
}
catch (System.Security.VerificationException) { }
Console.WriteLine(CodeGen.CreateDelegate<Func<Action>>(genfunc,owner:typeof(Program)).Invoke());
}
}
This code was written with the reflective library.
CodeGen.CreateDelegate simply uses the type parameter to determine the signature of the dynamic method. Here is the method::
public static TDelegate CreateDelegate<TDelegate>(
Action<ILGenerator> genfunc, string name = "", object target = null, Type owner = null, bool skipVisibility = false)
where TDelegate : class
{
var invokeMethod = typeof(TDelegate).GetMethod("Invoke");
var parameters = invokeMethod.GetParameters();
var paramTypes = new Type[parameters.Length + 1];
paramTypes[0] = typeof(object);
parameters.Select(p => p.ParameterType).ToArray().CopyTo(paramTypes, 1);
var method = owner != null ?
new DynamicMethod(name, invokeMethod.ReturnType, paramTypes, owner, skipVisibility) :
new DynamicMethod(name, invokeMethod.ReturnType, paramTypes, skipVisibility);
genfunc(method.GetILGenerator());
return method.CreateDelegate(typeof(TDelegate), target) as TDelegate;
}

Short answer
The code that you're trying to emit is unverifiable, and anonymously hosted dynamic methods can never contain unverifiable IL. Since dynamic methods associated with a type or module can contain unverifiable IL (subject to appropriate security checks), your code is usable from those dynamic methods.
Mode details
Despite MSDN's documentation, the ldvirtftn does not load a native int onto the stack; it loads a method pointer. Just as treating an object reference as a native int is valid but unverifiable, treating a method pointer as a native int is also valid but unverifiable. The easiest way to see this is to create an assembly on disk with the same IL instructions (e.g. by using System.Reflection.Emit or ilasm) and run PEVerify on it.
I believe that the only verifiable uses of method pointers are:
Constructing a delegate using the dup; ldvirtftn; newobj or ldftn; newobj patterns to create a new delegate of a compatible delegate type
Using calli with compatible arguments to make an indirect call through the method pointer
This explains why your other code can be called through an anonymously hosted dynamic method: the delegate creation pattern you are using is one of the few verifiable uses of a method pointer.

ldvirtfn loads a native int onto the stack. I think you need to convert that to IntPtr first before returning.

Strange behaviour (IntPtr != IntPtr):
//work normal
public static void F_Ldvirtftn_Action()
{
Action<ILGenerator> genfunc = il =>
{
il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldvirtftn, typeof(Program).GetMethod("Foo2"));
il.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
il.Emit(OpCodes.Ret);
};
Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
// failed: VerificationException: Operation could destabilize the runtime
public static void F_IntPtr_Action()
{
Action<ILGenerator> genfunc = il =>
{
il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Call, typeof(Program).GetMethod("Ptr"));
il.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
il.Emit(OpCodes.Ret);
};
Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
// failed: VerificationException: Operation could destabilize the runtime
public static void F_Ldvirtftn_MyAction()
{
Action<ILGenerator> genfunc = il =>
{
il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldvirtftn, typeof(Program).GetMethod("Foo2"));
il.Emit(OpCodes.Newobj, typeof(MyAction).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
il.Emit(OpCodes.Ret);
};
Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
//work normal
public static void F_IntPtr_MyAction()
{
Action<ILGenerator> genfunc = il =>
{
il.Emit(OpCodes.Newobj, typeof(Program).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Call, typeof(Program).GetMethod("Ptr"));
il.Emit(OpCodes.Newobj, typeof(MyAction).GetConstructor(new[] { typeof(object), typeof(IntPtr) }));
il.Emit(OpCodes.Ret);
};
Console.WriteLine(CreateDelegate<Func<object>>(genfunc).Invoke());
}
public static IntPtr Ptr(object z)
{
return IntPtr.Zero;
}
public class MyAction
{
public MyAction(object z, IntPtr adr) { }
}

Related

C# Create lambda over given method that injects first paramater

In C# I have following methods defined in given class (non static):
int MyMethod(ScriptEngine script, int a, int b) {
return a + b;
}
void MyMethod2(ScriptEngine script, string c) {
// do something with c
}
I want to create wrapping lambda / Action / Delegate / MethodInfo (all are accepted by script engine) that automatically passes ScriptEngine and this from given, predefined variables.
So far I've experimenting with:
// With overloads up to 16 template parameters
Action<T1> Wrap<T1>(Action<ScriptEngine, T1> func, ScriptEngine script) {
return (Action<T1>) ((t1) => func(script, t1));
}
But when called on MyMethod2 I've got The type arguments for method … cannot be inferred from the usage. Try specifying the type arguments explicitly. If I specify the template arguments explicity, it works, but I want to avoid such specification.
Is there any other way (not neccesery following my solution) I can create such wrapper automatically (or semi-automatically)?
It is worth mentioning that there is a dedicated abstract method void RegisterAll(ScriptEngine script) that can register required members of given subclass.
Here is an example of what I am trying to achieve:
class ScriptEngine { // Stub to have complete example, actual implementation is defined elsewhere
void RegisterApi(string name, MethodInfo methodInfo) { }
void RegisterApi(string name, Delegate delegateSelf) { }
}
class Api {
int MyMethod(ScriptEngine script, int a, int b) {
return a + b;
}
void MyMethod2(ScriptEngine script, string c) {
// do something with c
}
void RegisterAll(ScriptEngine script) {
// Is there any way to shorten this up (not providing MyMethod twice, not providing template arguments?)
script.RegisterApi(nameof(MyMethod), (Delegate)Wrap<string>(MyMethod, script));
}
}
The problem is how to improve this RegisterApi method so it:
Takes the method only once
Does not require specifying arguments via template method
There is actually another solution that does not involve emiting new Expressions (could fail on iOS!)
First, let us define following wrapper:
private class Wrapper
{
public readonly object container;
public readonly MethodInfo method;
public readonly ScriptEngine engine;
public Wrapper(object container, MethodInfo method, ScriptEngine engine)
{
this.container = container;
this.method = method;
this.engine = engine;
}
public Action CreateAction()
{
return () => method.Invoke(container, new object[] { engine });
}
public Action<T1> CreateAction<T1>()
{
return (arg1) => method.Invoke(container, new object[] { engine, arg1 });
}
// etc
}
Now you can register method like that:
var type = typeof(Wrapper);
var instance = Activator.CreateInstance(type, new object[] { container, methodInfo, engine });
MethodInfo methodActual = null;
if (methodInfo.ReturnType == typeof(void))
{
var methods = type.GetMethods().Where(x => x.Name == "CreateAction");
foreach (var method in methods)
{
if (method.GetGenericArguments().Length == methodInfo.GetParameters().Length - 1)
{
methodActual = method.MakeGenericMethod(methodInfo.GetParameters().Skip(1).Select(x => x.ParameterType).ToArray());
}
}
}
var actionToRegister = methodActual.Invoke(instance, new object[0]);
The solution is to use Expression Tree to create a simple delegate wrapper.
var parameterEngine = Expression.Constant(script, typeof(ScriptEngine));
var parameterCaller = Expression.Constant(this, this.GetType());
// Build parameters, skipping the first. Note that trailing "ToList" is important!
var parameters = methodInfo.GetParameters().Skip(1).Select(x => Expression.Parameter(x.ParameterType, x.Name)).ToList();
// Inject parameter
var mergedParameters = new List<Expression>();
mergedParameters.Add(parameterEngine);
mergedParameters.AddRange(parameters);
// Bind together
var call = Expression.Call(parameterCaller, methodInfo, mergedParameters);
var expression = Expression.Lambda(call, parameters);
var method = expression.Compile();
// Method can now be registered

How can I create a derived type from T, using System.Reflection.Emit

what I am having difficulties understanding is : what should I do in the build method?
It is our intent to implement a framework that has a method that generates a new instance of a class of domain in which their properties and methods have added functionalities.
The Following example presents a case of the creation of a object of domain Stock where the parameters passed to build will be pass as arguments to the constructor of stock in it's instantiation.
Enhancer.Build<Stock>("Apple", "Dow Jones");
The added functionalities are specified by custom attributes that mark the virtual methods and properties, as the following example shows. In the comments it is said what we intend the marked methods and properties to start verifying in the returned object from the function Build of Enhancer.
Every custom attribute in the example should have a common base type - EnhancedAtributte - with an abstract method Check(object[] args) that receives the arguments from the marked method.
class Stock
{
public Stock(string name, string index) { ... }
[NonNull]
public virtual string Market { get; set; } // set will launch an exception if values are null
[Min(73)]
public virtual long Quote { get; set; } // set will launch an exception if values are < 73
[Min(0.325)]
public virtual double Rate { get; set; } // set will launch an exception if values are < 0.325
[Accept("Jenny", "Lily", "Valery")]
public virtual string Trader{get; set; } // set will launch an exception if values are different than Jenny, Lily or Valery
[Max(58)]
public virtual int Price { get; set; } // set will launch an exception if values are > 58
// it will launch exception if the state of this or any of the parameters has been altered by the execution of a marked method
// -- BuildInterest
[NoEffects]
public double BuildInterest(Portfolio port, Store st) { ... }
}
Implementation strategies:
The project Enhancer must use the System.Reflection.Emit API.
The solution must not be compromised with the given examples.
A function Build(params object[] args) should return a new instance of a new class derived from T, let's call it T’, that
redefines the virtual methods of T.
The new class T’ is created dynamically with the API resource System.Reflection.Emit.
For each M method in T that is marked ( Custom Attribute), it should be created a new definition of the method M’ in class T’.
The
method M’ should call the base method M and should do the specified
by the custom attribute.
I'd start by verifying that T is neither sealed nor abstract. That should be sufficient to make sure it's (1) a class; and (2) capable of being extended.
Next, iterate over typeof(T).GetProperties() to find any 'enhanced' properties where CanWrite is true and property.GetCustomAttributes<EnhancedAtributte>().Any() reports true. If there aren't any matching properties, you can just instantiate T directly.
Since the property values are validated by the attribute instances themselves, you'll want to cache the attributes somewhere, lest you incur an expensive lookup on each property change. You should aim to generate a class that looks something like this:
public class __Enhanced__Stock__ {
private static readonly EnhancedAttribute[] __Price__Attributes__;
static __Enhanced__Stock__() {
__Price__Attributes__ = typeof(Stock).GetProperty("Price")
.GetCustomAttributes<EnhancedAtributte>()
.ToArray();
}
public override int Price {
get => base.Price;
set {
for (int i = 0, n = __Price__Attributes__.Length; i < n; i++)
__Price__Attributes__[i].Check(new Object[] { (Object)value });
}
base.Price = value;
}
}
}
A TypeBuilder can be created from a ModuleBuilder, which is created from an AssemblyBuilder. For the latter two, you can just keep a static instance around.
You'll need to use TypeBuilder.DefineField to define a static field to use as an attribute cache for each property (or use a single EnhancedAttribute[][] indexed by property). In either case, you'll have to define a class constructor (see TypeBuilder.DefineTypeInitializer) to initialize the cache. You'll have to write the IL yourself using MethodBuilder.GetILGenerator().
For each enhanced property you found, you'll need to define a new property with the same name (see TypeBuilder.DefineProperty), and emit a separate get and set accessor for each (see TypeBuilder.DefineMethod). Each accessor will need to be bound to the property, which can be accomplished via PropertyBuilder.SetGetMethod and SetSetMethod. You'll also have to make the accessors override the accessors in T, which you can do via TypeBuilder.DefineMethodOverride. You can see some hints on overriding properties in this question.
The code for the get accessor override will be simple: you need only delegate to the base property. The set accessor is more complicated, because you'll need to loop over the attribute cache for the property and call each attribute's Check method. Again, you'll need to emit the IL manually, which includes figuring out how to emit a simple for loop. Alternatively, since you already know the number of attributes for each property, you could just write a manually-unrolled loop. Regardless, for each call to Check, remember that you'll need to initialize a new object[] containing into which you must copy your value parameter.
Once you've declared the attribute cache field(s), the type initializer, the properties, and their accessors, you're essentially finished. You can 'bake' the derived type by calling CreateType() on your TypeBuilder.
Partial Solution
I felt like writing some code, so here's a solution that should handle the attribute-based property validation. It's not entirely clear to me how the attributes on other methods should work, but this should provide a good starting point nonetheless.
public class Enhancer
{
private static readonly ModuleBuilder ModuleBuilder;
static Enhancer()
{
var b = AssemblyBuilder.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()),
AssemblyBuilderAccess.Run);
ModuleBuilder = b.DefineDynamicModule($"{b.GetName().Name}.Module");
}
private const BindingFlags InstanceFlags = BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic;
private const FieldAttributes CacheFlags = FieldAttributes.Private |
FieldAttributes.Static |
FieldAttributes.InitOnly;
private const TypeAttributes TypeFlags = TypeAttributes.Public |
TypeAttributes.Sealed |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout |
TypeAttributes.AnsiClass;
private static IEnumerable<PropertyInfo> FindEnhancedProperties(Type t)
{
foreach (var p in t.GetProperties(InstanceFlags))
{
if (p.CanWrite &&
p.GetSetMethod(true).IsVirtual &&
p.IsDefined(typeof(EnhancedAttribute)))
{
yield return p;
}
}
}
public static EnhancedAttribute[] FindEnhancedAttributes(PropertyInfo p)
{
return p.GetCustomAttributes<EnhancedAttribute>().ToArray();
}
private static readonly MethodInfo CheckMethod =
typeof(EnhancedAttribute).GetMethod(
nameof(EnhancedAttribute.Check),
new[] { typeof(object[]) });
private static readonly MethodInfo GetTypeFromHandleMethod =
typeof(Type).GetMethod(
nameof(Type.GetTypeFromHandle),
new[] { typeof(RuntimeTypeHandle) });
private static readonly MethodInfo GetPropertyMethod =
typeof(Type).GetMethod(
nameof(Type.GetProperty),
new[] { typeof(string), typeof(BindingFlags) });
private static readonly MethodInfo FindEnhancedAttributesMethod =
typeof(Enhancer).GetMethod(
nameof(FindEnhancedAttributes),
new[] { typeof(PropertyInfo) });
private readonly Type _base;
private readonly TypeBuilder _enhanced;
private readonly PropertyInfo[] _properties;
private readonly FieldBuilder[] _attributeCaches;
private readonly MethodBuilder[] _propertySetters;
private static readonly Dictionary<Type, Type> Cache = new Dictionary<Type, Type>();
public static T Build<T>(params object[] args) where T : class
{
Type type;
lock (Cache)
{
if (!Cache.TryGetValue(typeof(T), out type))
Cache[typeof(T)] = type = new Enhancer(typeof(T)).Enhance();
}
return (T)Activator.CreateInstance(type, args);
}
private Enhancer(Type t)
{
if (t?.IsSealed != false || t.IsInterface)
{
throw new ArgumentException(
"Type must be a non-sealed, non-abstract class type.");
}
_base = t;
_enhanced = ModuleBuilder.DefineType($"<Enhanced>{t.FullName}", TypeFlags, t);
_properties = FindEnhancedProperties(t).ToArray();
_attributeCaches = _properties.Select(
p => _enhanced.DefineField(
$"__{p.Name}Attributes",
typeof(EnhancedAttribute[]),
CacheFlags)).ToArray();
_propertySetters = new MethodBuilder[_properties.Length];
}
private Type Enhance()
{
GenerateTypeInitializer();
for (int i = 0, n = _properties.Length; i < n; i++)
EnhanceProperty(i);
GenerateConstructors();
return _enhanced.CreateType();
}
private void GenerateConstructors()
{
var baseCtors = _base.GetConstructors(InstanceFlags);
foreach (var baseCtor in baseCtors)
{
if (baseCtor.IsPrivate)
continue;
var parameters = baseCtor.GetParameters();
var ctor = _enhanced.DefineConstructor(
baseCtor.Attributes,
baseCtor.CallingConvention,
parameters.Select(p => p.ParameterType).ToArray());
var il = ctor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
for (int i = 0; i < parameters.Length; i++)
il.Emit(OpCodes.Ldarg, i + 1);
il.Emit(OpCodes.Call, baseCtor);
il.Emit(OpCodes.Ret);
}
}
private void GenerateTypeInitializer()
{
var typeInit = _enhanced.DefineTypeInitializer();
var il = typeInit.GetILGenerator();
for (int i = 0, n = _properties.Length; i < n; i++)
{
var p = _properties[i];
il.Emit(OpCodes.Ldtoken, _base);
il.EmitCall(OpCodes.Call, GetTypeFromHandleMethod, null);
il.Emit(OpCodes.Ldstr, p.Name);
il.Emit(OpCodes.Ldc_I4_S, (int)InstanceFlags);
il.EmitCall(OpCodes.Call, GetPropertyMethod, null);
il.EmitCall(OpCodes.Call, FindEnhancedAttributesMethod, null);
il.Emit(OpCodes.Stsfld, _attributeCaches[i]);
}
il.Emit(OpCodes.Ret);
}
private void EnhanceProperty(int index)
{
var p = _properties[index];
var property = _enhanced.DefineProperty(
p.Name,
p.Attributes,
p.PropertyType,
null);
var baseSet = p.GetSetMethod(true);
var set = _enhanced.DefineMethod(
baseSet.Name,
baseSet.Attributes & ~MethodAttributes.NewSlot | MethodAttributes.Final,
baseSet.CallingConvention,
baseSet.ReturnType,
new[] { p.PropertyType });
property.SetSetMethod(set);
_enhanced.DefineMethodOverride(set, baseSet);
var il = set.GetILGenerator();
var attributeCount = p.GetCustomAttributes<EnhancedAttribute>().Count();
for (int j = 0; j < attributeCount; j++)
{
il.Emit(OpCodes.Ldsfld, _attributeCaches[index]);
il.Emit(OpCodes.Ldc_I4, j);
il.Emit(OpCodes.Ldelem_Ref, j);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg_1);
if (p.PropertyType.IsValueType)
il.Emit(OpCodes.Box, p.PropertyType);
il.Emit(OpCodes.Stelem_Ref);
il.EmitCall(OpCodes.Callvirt, CheckMethod, null);
}
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.EmitCall(OpCodes.Call, baseSet, null);
il.Emit(OpCodes.Ret);
_propertySetters[index] = set;
}
}

How to call Action<string, bool> from il generator

In this example code i am trying to invoke a anonymous action from il generator. I am not sure if and how i can load the reference to the delegate and how to call it.
I can do it if the OnFunctionCall is a static method not property.
public delegate void TestDelegate();
public static class ExampleOne
{
public static Action<string, bool> OnFunctionCall
=> (message, flag) => Console.WriteLine("Example");
}
public static class ExampleTwo
{
public static TType CreateDelegate<TType>(Action<string, bool> onFunctionCall)
where TType : class
{
var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);
ILGenerator il = method.GetILGenerator();
// Emit some code that invoke unmanaged function ...
// loading the first string argument
il.Emit(OpCodes.Ldstr, method.Name);
// not sure here how to load boolean value to the stack
il.Emit(OpCodes.Ldc_I4_0);
// this line doesn't work
// example two has no idea about ExampleOne
// is it possible to load the reference of the Action<string, bool> to the stack and call it ?
il.Emit(OpCodes.Call, onFunctionCall.Method);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(TestDelegate)) as TType;
}
}
public class Program
{
public static void Main(string[] args)
=> ExampleTwo
.CreateDelegate<TestDelegate>(ExampleOne.OnFunctionCall)
.Invoke();
}
You have to pass the information where the delegate you want to invoke is stored. The convenience way is to accept a MemberExpression, otherwise accepting a MemberInfowould work too. Have a look at your modified code:
public delegate void TestDelegate();
public static class ExampleOne
{
public static Action<string, bool> OnFunctionCall
=> (message, flag) => Console.WriteLine("OnFunctionCall");
public static Action<string, bool> OnFunctionCallField
= (message, flag) => Console.WriteLine("OnFunctionCallField");
}
public static class ExampleTwo
{
public static TType CreateDelegate<TType>(Expression<Func<object>> expression)
where TType : class
{
var body = expression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException(nameof(expression));
}
var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);
ILGenerator il = method.GetILGenerator();
// Get typed invoke method and
// call getter or load field
MethodInfo invoke;
if (body.Member is PropertyInfo pi)
{
invoke = pi.PropertyType.GetMethod("Invoke");
il.Emit(OpCodes.Call, pi.GetGetMethod());
}
else if (body.Member is FieldInfo fi)
{
invoke = fi.FieldType.GetMethod("Invoke");
il.Emit(OpCodes.Ldsfld, fi);
}
else
{
throw new ArgumentException(nameof(expression));
}
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Callvirt, invoke);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(TestDelegate)) as TType;
}
}
public class Program
{
public static void Main(string[] args)
{
ExampleTwo
.CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCall)
.Invoke();
ExampleTwo
.CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCallField)
.Invoke();
Console.ReadLine();
}
}
The code is running on .Net Core 2.0.

I want to get a method by reflection

I want to get a method by reflection,but the method has multiple overloads..and the method's parameters is a generic type..How can I do?
class Program
{
static void Main(string[] args)
{
test obj = new test();
Type[] types = { typeof(string) };
var method = obj.GetType().GetMethod("Say", BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);
method.Invoke(obj, new object[] { "hello world" });
Console.ReadKey();
}
}
public class test
{
private void Say(string value)
{
Console.WriteLine(value);
}
private void Say<T>(T t)
{
Console.WriteLine(t);
}
}
I can get private void Say(string value)..but I want to get private void Say<T>(T t)..
Type[] types = { typeof(string) }; Here how to set up here?
Based on the comments, I would rather go for a solution like:
public static MethodInfo GetGenericMethod(object obj, string methodName, Type genericParameter)
{
var method = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(m => m.Name.Equals(methodName) && m.IsGenericMethod);
return method.MakeGenericMethod(genericParameter);
}
And then call it with something like:
GetGenericMethod(obj, "Say", typeof(string));
You will then be able to invoke it like any other methods.
There are you ways.
Get all methods and find that one you're looking for
obj.GetType().GetMethods().Single(m=>m.GetParameters().Length = /* parameter count*/ && /* next condition */);
Use Expression tree
In my opinion is nicer and less error prone but can be used only when you known which method you want in compile time.
You need some helper method that extract Method for expression tree.
public static MethodInfo Method(Expression<Action> methodAccess)
{
return ((MethodCallExpression)methodAccess.Body).Method;
}
Then you can use it like this:
Get(()=>obj.Say<string>("My param")).GetGenericMethodDefinition();
Compiler will take care of selecting method and helper method will extract MethodInfo from expression tree. GetGenericMethodDefinition() call will give you open-generic version of selected method.

Function pointers in C#

I suppose in some ways either (or both) Delegate or MethodInfo qualify for this title. However, neither provide the syntactic niceness that I'm looking for. So, in short, Is there some way that I can write the following:
FunctionPointer foo = // whatever, create the function pointer using mechanisms
foo();
I can't use a solid delegate (ie, using the delegate keyword to declare a delegate type) because there is no way of knowing till runtime the exact parameter list. For reference, here's what I've been toying with in LINQPad currently, where B will be (mostly) user generated code, and so will Main, and hence for nicety to my users, I'm trying to remove the .Call:
void Main()
{
A foo = new B();
foo["SomeFuntion"].Call();
}
// Define other methods and classes here
interface IFunction {
void Call();
void Call(params object[] parameters);
}
class A {
private class Function : IFunction {
private MethodInfo _mi;
private A _this;
public Function(A #this, MethodInfo mi) {
_mi = mi;
_this = #this;
}
public void Call() { Call(null); }
public void Call(params object[] parameters) {
_mi.Invoke(_this, parameters);
}
}
Dictionary<string, MethodInfo> functions = new Dictionary<string, MethodInfo>();
public A() {
List<MethodInfo> ml = new List<MethodInfo>(this.GetType().GetMethods());
foreach (MethodInfo mi in typeof(Object).GetMethods())
{
for (int i = 0; i < ml.Count; i++)
{
if (ml[i].Name == mi.Name)
ml.RemoveAt(i);
}
}
foreach (MethodInfo mi in ml)
{
functions[mi.Name] = mi;
}
}
public IFunction this[string function] {
get {
if (!functions.ContainsKey(function))
throw new ArgumentException();
return new Function(this, functions[function]);
}
}
}
sealed class B : A {
public void SomeFuntion() {
Console.WriteLine("SomeFunction called.");
}
}
You say you want to keep the number and type of parameters open, but you can do that with a delgate:
public delegate object DynamicFunc(params object[] parameters);
This is exactly the same thing you currently have. Try this:
class Program
{
static void Main(string[] args)
{
DynamicFunc f = par =>
{
foreach (var p in par)
Console.WriteLine(p);
return null;
};
f(1, 4, "Hi");
}
}
You can think of an instance-method delegate as very similar to your Function class: an object an a MethodInfo. So there's no need to rewrite it.
Also function pointers in C and C++ are not any closer to what you need: they cannot be bound to an object instance and function, and also they are statically typed, not dynamically typed.
If you want to "wrap" any other method in a DynamicFunc delegate, try this:
public static DynamicFunc MakeDynamicFunc(object target, MethodInfo method)
{
return par => method.Invoke(target, par);
}
public static void Foo(string s, int n)
{
Console.WriteLine(s);
Console.WriteLine(n);
}
and then:
DynamicFunc f2 = MakeDynamicFunc(null, typeof(Program).GetMethod("Foo"));
f2("test", 100);
Note that I'm using a static method Foo so I pass null for the instance, but if it was an instance method, I'd be passing the object to bind to. Program happens to be the class my static methods are defined in.
Of course, if you pass the wrong argument types then you get errors at runtime. I'd probably look for a way to design your program so that as much type information is captured at compile time as possible.
Here's another bit of code you could use; Reflection is rather slow, so if you expect your Dynamic function calls to be called frequently, you don't want method.Invoke inside the delegate:
public delegate void DynamicAction(params object[] parameters);
static class DynamicActionBuilder
{
public static void PerformAction0(Action a, object[] pars) { a(); }
public static void PerformAction1<T1>(Action<T1> a, object[] p) {
a((T1)p[0]);
}
public static void PerformAction2<T1, T2>(Action<T1, T2> a, object[] p) {
a((T1)p[0], (T2)p[1]);
}
//etc...
public static DynamicAction MakeAction(object target, MethodInfo mi) {
Type[] typeArgs =
mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
string perfActName = "PerformAction" + typeArgs.Length;
MethodInfo performAction =
typeof(DynamicActionBuilder).GetMethod(perfActName);
if (typeArgs.Length != 0)
performAction = performAction.MakeGenericMethod(typeArgs);
Type actionType = performAction.GetParameters()[0].ParameterType;
Delegate action = Delegate.CreateDelegate(actionType, target, mi);
return (DynamicAction)Delegate.CreateDelegate(
typeof(DynamicAction), action, performAction);
}
}
And you could use it like this:
static class TestDab
{
public static void PrintTwo(int a, int b) {
Console.WriteLine("{0} {1}", a, b);
Trace.WriteLine(string.Format("{0} {1}", a, b));//for immediate window.
}
public static void PrintHelloWorld() {
Console.WriteLine("Hello World!");
Trace.WriteLine("Hello World!");//for immediate window.
}
public static void TestIt() {
var dynFunc = DynamicActionBuilder.MakeAction(null,
typeof(TestDab).GetMethod("PrintTwo"));
dynFunc(3, 4);
var dynFunc2 = DynamicActionBuilder.MakeAction(null,
typeof(TestDab).GetMethod("PrintHelloWorld"));
dynFunc2("extraneous","params","allowed"); //you may want to check this.
}
}
This will be quite a bit faster; each dynamic call will involve 1 typecheck per param, 2 delegate calls, and one array construction due to the params-style passing.

Categories

Resources