You can pass in a method into another method that's takes Func<>. But can you pass that in as a dynamically named string so you can what method is passed in on the fly?
You can pass in a method into another method that's takes Func<>.
It's worth separating out the "passing a value" from "creating the value in the first place". When you write code such as:
InvokeSomeDelegate(MethodToInvoke);
That's performing a method group conversion to create a delegate instance. In other words, it's equivalent to:
Func<Whatever> func = MethodToInvoke;
InvokeSomeDelegate(func);
So really the question isn't so much about how you can pass a string into the method, as how to create a delegate based on a string. That in turn leads to the question of what kind of method, what type it's in etc.
The framework method you want to use is Delegate.CreateDelegate, but exactly how you use that will depend on the context, so that you can find the right MethodInfo with reflection. Here's an example:
using System;
using System.Reflection;
class Test
{
static void Main()
{
InvokeFunc("Double");
InvokeFunc("Quadruple");
InvokeFunc("AddOne");
}
static void InvokeFunc(string name)
{
// Note that in our case they're all private static methods. You'd
// need to adjust the binding flags if that's not the case. If you
// need to worry about multiple overloads, that makes it harder too.
MethodInfo method = typeof(Test)
.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static);
// TODO: Validate that you've got a method
var func = (Func<int, int>) Delegate.CreateDelegate(
typeof(Func<int, int>), // Delegate type to create
null, // Target of method call; null because ours are static
method); // Method to create a delegate for
var result = func(10);
Console.WriteLine($"{name}(10) => {result}");
}
static int Double(int x) => x * 2;
static int Quadruple(int x) => x * 4;
static int AddOne(int x) => x + 1;
}
Note that all the reflection to find the method and then create the delegate is relatively slow. If you're doing this with any significant performance constraints, you may want to add caching.
Related
Heyo,
i'm currently working on a school assignment and we should use delegate's.
So I got a delegate:
public delegate AVLNode Insert(AVLNode node, dynamic key);
And I got two different Insert Methods, the one takes a node and a string and the other one should take a node and a float as a paramter.
The problem I face now is that the delegate doesn't accept these method's because they don't match.
How can I fix tis issue without declaring the string and the int parameter as a dynamic? Sorry if my problem isn't described well, first time describing any coding problem.
Like I already said, I want a delegate with a dynamic as the parameter while both methods which will be used with the delegate have either a string or a int as the parameter.
Out of curiosity, why do you want a dynamic parameter for your key over an object which is also accepting of every type? You can then use pattern matching to ensure they are either a float or a string since you can't overload delegates. Making something dynamic also involves a lot of type checking during runtime. Why a delegate for an insert method? Do you want users to write their own insert method into a collection I assume is managed by a class? That makes no guarantee the insert delegate will insert successfully.
Generally, you mostly see delegates being used as guaranteed signatures that fulfill an operation that the user defines. For example: TimerCallback being a delegate for what happens every time a timer ticks, SpanAction<T, TArg> for letting users work with a given span and state object, custom events letting users create their own operations when something occurs, etc.
Anyways, wherever you're using your delegate, you want to make sure it is either a string or a float/int (you used both float and int seemingly interchangeably in your description). You can use this example to check for both types:
public static void Main()
{
var dyn = func(); // Returns dynamic, unknown type
if (dyn is string s)
Console.WriteLine($"string: {s}");
else if (dyn is int i)
Console.WriteLine($"int: {i}");
else if (dyn is float f) Console.WriteLine($"float: {f}");
}
Or you can use regular if statements:
public static void Main()
{
var dyn = func(); // Returns dynamic, unknown type
switch (dyn)
{
case string s:
Console.WriteLine($"string: {s}");
break;
case int i:
Console.WriteLine($"int: {i}");
break;
case float f:
Console.WriteLine($"float: {f}");
break;
}
}
But seriously, I cannot stress this enough: everything you want can very likely just be done with the object type!!! While both object and dynamic types allow for any object, dynamic allows for even specified derived types to be reassigned to any other type! For example:
public static void Main()
{
var dyn = GetDynamicInt(); // dynamic int
var n = GetInt(); // not dynamic int
dyn = Random.Shared.NextDouble(); // Now it's not an int but do you know that? Will you know that?
n = Random.Shared.NextDouble(); // Guaranteed type, this throws
}
I want to write a function that takes a function as an argument and then do different things based on whether the passed-in function returns void vs a value.
C# signature checking can't tell the difference so I'm stuck doing it in code.
Is there an easy way to test whether an arbitrary function returns void?
To be clear. I explicitly am not interested in a compile error. I just want the equivalent of what I can do for any other object.
void IsString(object o) => o is string;
void ElseWhere() {
object o = 1;
if (IsString(o)) Bla();
However even this gets a compile error claiming the two methods are ambiguous. It doesn't flag the methods themselves ambiguous but I get an error on the call saying it can't resolve between them.
private static bool HasNoReturnValue(Action o) => true;
private static bool HasNoReturnValue(Func<object> o) => false;
...
if (HasNoReturnValue(SomeFunction)) Bla();
As do anything I've tried involving typeof:
if (SomeFunction is typeof(Func(object>)) Bla();
Let's say you have two methods, one of which returns a Boolean and one which returns void.
void SomeFunction1()
{
}
bool SomeFunction2()
{
return false;
}
To pass either of these as a pointer to a method, you have to convert them to a delegate. Two types of delegates: Action and Func<bool>, respectively:
var action1 = new Action(SomeFunction1);
var action2 = new Func<bool>(SomeFunction2);
You can then write two methods that accept these types as arguments:
void AcceptDelegate(Action action)
{
Console.WriteLine("The delegate returns void.");
}
void AcceptDelegate(Func<bool> func)
{
Console.WriteLine("The delegate returns a Boolean.");
}
And call them like this:
AcceptDelegate(action1);
AcceptDelegate(action2);
Or you could pass the method group directly and the compiler will figure out the type (Why? See the Microsoft documentation on c# method group conversions):
AcceptDelegate(SomeFunction1);
AcceptDelegate(SomeFunction2);
Either way you call them, you would get this output:
The delegate returns void.
The delegate returns a Boolean.
The reason this works is the compiler will automatically pick the right one at compile-time, based on the type of the delegate, just as it would pick the overload for any type such as string or integer. This is the type-safe / early-bound way to do it.
If you insist on an "any delegate"/ late binding sort of approach, you could do something like this:
void AcceptAnyDelegate(Delegate anyAction)
{
Console.WriteLine("The function returns a {0}", anyAction.Method.ReturnType);
}
Because the signature isn't type specific, you have to pass the specific delegates this time (Why? See this answer):
AcceptAnyDelegate(action1);
AcceptAnyDelegate(action2);
And the output would be:
The function returns a Void
The function returns a Boolean
Edit
After rereading your comments, I believe the confusion here is due to a misunderstanding of method groups and delegates.
When you write something like this:
Foo(Bar);
...it appears you believe you are passing to Foo a direct reference to the Bar method. That is not correct. What you are doing is specifying a method group, which the compiler can then use to infer the type of delegate to pass. If Bar is a method with no inputs or outputs, the above code is exactly the same as
Foo(new Action( Bar ));
...only the creation of the delegate is hidden from you by the compiler.
All delegates are specifically typed with respect to their parameters and return type. The Delegate base type is abstract and cannot exist in concrete form. So there is no such thing as passing a type-agnostic function reference-- it doesn't exist in c#.
If you really really want to pass something that is type-agnostic, you can ask the caller to pass a lambda expression:
Foo( () => SomeFunction1() );
You could then parse the expression to figure out the method's inputs and outputs:
void Foo(Expression<Action> anyAction)
{
var mce = anyAction.Body as MethodCallExpression;
var method = mce.Method;
Console.WriteLine("The method has a return type of {0}", method.ReturnType.Name);
}
Then to invoke the expression you would use:
var compiled = anyAction.Compile();
compiled();
That is the closest you're going to get.
There's two different types here:
Action for no return type
and
Func for a return type
Can you make two different signatures for these two different argument types?
This will do the trick
public static void TakeInAFunc<T>(T aFuncOrAction)
{
if (typeof(T) == typeof(Func<>))
{
// some value returned.
}
else if (typeof(T) == typeof(Action<>))
{
// it returns void.
}
}
I am currently using Calling a method of existing object using IL Emit as a guide, and I can already do whatever is asked in question. Now, I have an attribute added to a parameter and I want to load that particular parameter's attribute so that I can call a method inside that attribute.
I know it can be done by loading the MethodInfo and then getting the ParameterInfo and then getting attribute of that ParameterInfo in IL; I am simply trying to avoid writing that much IL.
Is there a way to load a parameter's attribute in IL just like it is mentioned in the linked post?
Edit:
I have a method with a signature like
Method([Attr] int Parameter)
and I want to load a method which is part of the Attr. I was just hoping I could load ParameterInfo (obtained using MethodInfo.GetParameters()) directly onto the stack. Turns out, LdToken doesn't really allow putting ParameterInfo. Only other way I can think of doing this is to load MethodInfo (LdToken supports that) and then use GetParameters() in IL to get an array of Parameters and then loop through them in IL one by one to get each one's Attribute (using .GetCustomAttribute(Type)) and then call the method on that attribute. Note that I don't have to get a field of an attribute, I need to call a method on that attribute.
K, third time lucky based on another interpretation of the question; here, we're assuming that we want to invoke methods on an attribute instance. We need to consider that attributes only kinda sorta exist at runtime - we can create synthetic instances of the attribute as represented by the metadata, but this isn't particularly cheap or fast, so we should ideally only do this once (the metadata isn't going to change, after all). This means we might want to store the instance as a field somewhere. This could be an instance field, or a static field - in many cases, a static field is fine. Consider:
using System;
using System.Reflection;
using System.Reflection.Emit;
public class SomethingAttribute : Attribute
{
public SomethingAttribute(string name)
=> Name = name;
public string Name { get; }
public void SomeMethod(int i)
{
Console.WriteLine($"SomeMethod: {Name}, {i}");
}
}
public static class P
{
public static void Foo([Something("Abc")] int x)
{
Console.WriteLine($"Foo: {x}");
}
public static void Main()
{
// get the attribute
var method = typeof(P).GetMethod(nameof(Foo));
var p = method.GetParameters()[0];
var attr = (SomethingAttribute)Attribute.GetCustomAttribute(p, typeof(SomethingAttribute));
// define an assembly, module and type to play with
AssemblyBuilder asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Evil"), AssemblyBuilderAccess.Run);
var module = asm.DefineDynamicModule("Evil");
var type = module.DefineType("SomeType", TypeAttributes.Public);
// define a field where we'll store our synthesized attribute instance; avoid initonly, unless you're
// going to write code in the .cctor to initialize it; leaving it writable allows us to assign it via
// reflection
var attrField = type.DefineField("s_attr", typeof(SomethingAttribute), FieldAttributes.Static | FieldAttributes.Private);
// declare the method we're working on
var bar = type.DefineMethod("Bar", MethodAttributes.Static | MethodAttributes.Public, typeof(void), new[] { typeof(int) });
var il = bar.GetILGenerator();
// use the static field instance as our target to invoke the attribute method
il.Emit(OpCodes.Ldsfld, attrField); // the attribute instance
il.Emit(OpCodes.Ldarg_0); // the integer
il.EmitCall(OpCodes.Callvirt, typeof(SomethingAttribute).GetMethod(nameof(SomethingAttribute.SomeMethod)), null);
// and also call foo
il.Emit(OpCodes.Ldarg_0); // the integer
il.EmitCall(OpCodes.Call, typeof(P).GetMethod(nameof(P.Foo)), null);
il.Emit(OpCodes.Ret);
// complete the type
var actualType = type.CreateType();
// assign the synthetic attribute instance on the concrete type
actualType.GetField(attrField.Name, BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, attr);
// get a delegate to the method
var func = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), actualType.GetMethod(bar.Name));
// and test it
for (int i = 0; i < 5; i++)
func(i);
}
}
Output from the final loop (for (int i = 0; i < 5; i++) func(i);):
SomeMethod: Abc, 0
Foo: 0
SomeMethod: Abc, 1
Foo: 1
SomeMethod: Abc, 2
Foo: 2
SomeMethod: Abc, 3
Foo: 3
SomeMethod: Abc, 4
Foo: 4
As a side note; in many ways it is easier to do this with expression-trees, since expression-trees have Expression.Constant which can be the attribute instance, and which is treated like a field internally. But you mentioned TypeBuilder, so I went this way :)
I know it can be done by loading the MethodInfo and then getting the ParameterInfo and then getting attribute of that ParameterInfo in IL; I am simply trying to avoid writing that much IL.
Yeah, that's pretty much it, in IL; IL is powerful, but is not particularly terse or simple. Just like in the linked post, you'd end up loading the parameter (ldarg or ldarga, maybe some .s), then depending on whether the member is a field or a property, using either ldfld or callvirt on the property getter. About 3 lines, so not huge; perhaps something like:
static void EmitLoadPropertyOrField(ILGenerator il, Type type, string name)
{
// assumes that the target *reference* has already been loaded; only
// implements reference-type semantics currently
var member = type.GetMember(name, BindingFlags.Public | BindingFlags.Instance).Single();
switch (member)
{
case FieldInfo field:
il.Emit(OpCodes.Ldfld, field);
break;
case PropertyInfo prop:
il.EmitCall(OpCodes.Callvirt, prop.GetGetMethod(), null);
break;
default:
throw new InvalidOperationException();
}
}
If you're trying to save complexity (or are sick of InvalidProgramException), another viable approach is to use expression trees; then you have many more convenience features, but in particular things like:
var p = Expression.Parameter(typeof(Foo), "x");
var name = Expression.PropertyOrField(p, "Name");
// ...
var lambda = Expression.Lambda<YourDelegateType>(body, p);
var del = lambda.Compile();
Note that expression trees cannot be used in all scenarios; for example, they can't really be used with TypeBuilder; conversely, though, they can do things that IL-emit can't - for example, in AOT scenarios where IL-emit is prohibited, they can work as a runtime reflection evaluated tree, so it still works (but: slower). They add some additional processing (building and then parsing the tree), but: they are simpler than IL-emit, especially for debugging.
With the clarification that by attribute you really did mean a .NET attribute (not a field or property), this becomes simpler in many ways; consider:
class SomethingAttribute : Attribute
{
public SomethingAttribute(string name)
=> Name = name;
public string Name { get; }
}
static class P
{
public static void Foo([Something("Abc")] int x) {}
static void Main()
{
var method = typeof(P).GetMethod(nameof(Foo));
var p = method.GetParameters()[0];
var attr = (SomethingAttribute)Attribute.GetCustomAttribute(
p, typeof(SomethingAttribute));
string name = attr?.Name;
// you can now "ldstr {name}" etc
}
}
The important point here is that the attribute isn't going to change at runtime - it is pure metadata; so, we can load it once with reflection when we are processing the model, then just emit the processed data, i.e. the line
// you can now "ldstr {name}" etc
For future reference, I actually went ahead and loaded ParameterInfo using IL only. Marc's solution was good, but it quickly became infeasible after the number of parameter based attributes increased. We plan to use attributes to contain some state specific information, we would have to use a ton of reflection from outside the type to find and assign correct attribute to the field. Overall, it would have become quite hectic to deal with it.
To load ParameterInfo using IL
IL.Emit(OpCodes.Ldtoken, Method); // Method is MethodInfo as we can't use GetParameters with MethodBuilder
IL.Emit(OpCodes.Call, typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), new[] { typeof(RuntimeMethodHandle) }));
IL.Emit(OpCodes.Callvirt, typeof(MethodInfo).GetMethod(nameof(MethodInfo.GetParameters)));
var ILparameters = IL.DeclareLocal(typeof(ParameterInfo[]));
IL.Emit(OpCodes.Stloc, ILparameters);
that loads ParameterInfo onto stack and then stores it into a LocalBuilder called ILparameters. Note that it is an array. Items of this array can then be accessed like
IL.Emit(OpCodes.Ldloc, ILparameters);
IL.Emit(OpCodes.Ldc_I4, Number); // Replace with Ldc_I4_x if number < 8
IL.Emit(OpCodes.Ldelem_Ref);
I prefer to create two helper functions for the two code pieces. It works pretty well.
I have a generic function CallLater that should accept an arbitrary other function and possibly call it later with some parameters. All kind of functions should be supported - static, instance, private, public. Parameters are analyzed and constructed dynamically in CallLater with the help of reflection. However, some of them may need to be bound to fixed values before passing the function to the CallLater.
For example:
void CallLater(Delegate d) {
// Expects a function that returns string and has one argument of arbitrary type.
if (d.Method.GetParameters().Length == 1 &&
d.Method.ReturnType == typeof(string)) {
object param1 = Activator.CreateInstance(d.Method.GetParameters()[0].ParameterType);
Console.WriteLine((string)d.DynamicInvoke(param1));
}
}
// Has one extra float parameter.
string MyFunc(int a, float b) { ... }
My idea was to do something like that:
float pi = 3.14f;
CallLater(delegate(int a) { return MyFunc(a, pi); });
But this doesn't work as compiler complains:
Error CS1660: Cannot convert `anonymous method' to non-delegate type `System.Delegate' (CS1660) (test-delegate)
What is the correct approach to achieve my goal?
P.S. Please do not offer the solution to declare a fixed delegate type as CallLater is way more complex and may support variable number of arguments too.
P.P.S. It might be that my solution is Func, but I wasn't able to use it on Mono so far.
You can always redeclare Func yourself:
public delegate TReturn FFunc<TArg,TReturn>(TArg arg);
Which you can use thusly:
float pi = 3.14f;
CallLater((FFunc<int,string>)(delegate(int a) { return MyFunc(a, pi); }));
I'd suggest using anonymous functions in which you call the method you want to execute. These are executed later when the anonymous method is executed.
private static void ExecuteBoolResult(Func<bool> method)
{
bool result = method();
if (!result)
{
throw new InvalidOperationException("method did not return true");
}
}
CheckBoolResult(() => AnotherFunction("with ", 3, " parameters"));
CheckBoolResult(() => AnotherFunction(2, "parameters"));
I'm having trouble emitting a call to a delegate whose type is unfinished at the time of the emit. I'll elaborate: I've declared the following delegate type:
// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open
// instance method: the implicit argument is here given explicitly, in
// 'firstArgument'. (See link below for explanation on open instance delegates).
public delegate Object DirectReadAccessor<T>(T firstArgument);
And now I'm trying to dynamically (i.e., with a TypeBuilder) create the following class:
public MyClass {
// Array of delegates. T has been replaced with MyClass because the
// argument will be 'this', which is of type MyClass.
private static DirectReadAccessor<MyClass>[] directReadAccessors;
// Method that looks up a delegate in the array of delegates and calls it
// with 'this'.
public Object DirectRead(int i) {
directReadAccessors[i](this);
}
// Method that is called by the declaring type to pass an array with the
// MethodInfo of some methods. MyClass then creates delegates for these
// methods and stores them in the directReadAccessors array.
public static void InitializeClass(MethodInfo[] directReadAccessorsMInfo) {
int length = directReadAccessorsMInfo.Length;
Type[] typeArguments = new Type[] { typeof(MyClass) };
directReadAccessors = new DirectReadAccessor<MyClass>[length];
// For each method in directReadAccessorsMInfo...
for (int i = 0; i < length; i++) {
// Create a delegate and store it in directReadAccessors.
directReadAccessors[i] = (DirectReadAccessor<MyClass>)
Delegate.CreateDelegate(
DirectReadAccessor<MyClass>, // Type of the delegate.
null, // Specify null first argument so that it's
// *open* instance.
directReadAccessorsMInfo[i].MakeGenericMethod(typeArguments) // The method.
);
}
}
}
*on open instance delegates.
This has been tricky because MyClass doesn't exist when I'm trying to declare the field directReadAccessors, which is of type DirectReadAccessor[], or when I emit the method InitalizeClass, which again uses MyClass, that doesn't exist yet (that's what I'm creating). However, I've managed to do all this, but now I'm having trouble with method DirectRead, since I don't know how to call the delegate once I have it on the stack. Apparently what I need is the following emit:
ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);
where invokeMInfo is the method Invoke on DirectReadAccessor, and which I should obtain like so:
MethodInfo invokeMInfo = typeof(DirectReadAccessor<MyClass>).GetMethod(
"Invoke", // Name of the method.
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, // Binding attributes.
null, // Binder.
new Type[] { typeof(MyClass) }, // Types of the arguments.
null // Modifiers for the arguments.
);
Again, the problem is that neither MyClass nor DirectReadAccessor exist yet. I have the TypeBuilder for MyClass and the unfinished DirectReadAccessor type, which I've created like this:
directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);
But if I try to call GetMethod("Invoke", ....) on directReadAccessorType as shown above I get a NotSupportedException, because I cannot obtain the method Invoke for an unfinished type. I've tested this assumption by making the same call after finalizing the type with:
typeBuilder.CreateType();
And indeed I do not get the exception in that case. However, I need to be able to get the Invoke method's MethodInfo before finalizing the type, while I'm emitting the code for InitializeClass.
It's a strange situation: I'll have the delegate when I need it, but I cannot produce the code to invoke it. Can anyone offer any help?
Thanks so much, and sorry for the lengthy post.
That's a tricky problem. I think that you should be able to use TypeBuilder.GetMethod to get the MethodInfo you need, using a call along the lines of
TypeBuilder.GetMethod(directReadAccessorType,
typeof(DirectReadAccessor<>).GetMethod("Invoke"));
Have you tried to compile the generic code and look at it using ILDASM ? It should show you the correct IL and hopefully the right emit to generate.
Would it make sense to minimize the amount of code in the generated class ?
By that, I mean that the generated class could implement an interface that gives access to its data. Through it, you could implement additional features that could be coded in C# instead of IL.