Creating a function dynamically at run-time
Asked Answered
T

8

10

It probably isn't even possible to do this, but I will ask anyway. Is it possible to create a function that receives a string and then uses it as a right side argument for the goes to operator (=>) used in lambda?

Actually, what I want to do is to be able to redefine an specific method of a specific class during runtime. I want to be write down a function with the program running and attaching it to a delegate. Is it possible?

Tapdance answered 3/7, 2009 at 16:23 Comment(3)
Could you tell us what is your actual use case? May be there is some other way to address your requirement.Townsley
If I'm reading that correctly, you want to eval() a string? en.wikipedia.org/wiki/EvalProficiency
@Proficiency It is apparently possible to eval() a string in C# using one of the methods described here.Stevana
A
10

The easiest way to do it is probably DLINQ as TcKs suggested.

The fastest (I believe, in 3.5) is to create a DynamicMethod. Its also the scariest method as well. You're essentially building a method using IL, which has about the same feel as writing code in machine language.

I needed to do this to dynamically attach event handlers in some thing or another (well, I didn't need to do it, I just wanted to make unit testing events easier). It seemed a bit daunting at the time because I don't know crap about IL, but I figured out a simple way to accomplish this.

What you do is create a method that does exactly what you want. The more compact the better. I'd provide an example if I could figure out exactly what you're trying to do. You write this method in a class within a DLL project and compile it in release mode. Then you open the DLL in Reflector and disassemble your method. Reflector gives you the option of what language you wish to disassemble to--select IL. You now have the exact calls you need to add to your dynamic method. Just follow the example on MSDN, switching out the example's IL for your reflected methods' code.

Dynamic methods, once constructed, invoke at about the same speed as compiled methods (saw a test where dynamic methods could be called in ~20ms where reflection took over 200ms).

Anesthetize answered 3/7, 2009 at 16:47 Comment(2)
WoW, and here I thought I knew something about .NET. And I never heard of it. I am afraid of asking how did you ever manage to stumble upon such feature.Tapdance
DynamicMethod is available since 2.0Sharlenesharline
N
11

You have several ways how to do it:

Nightgown answered 3/7, 2009 at 16:33 Comment(1)
I wish I could pick both answers as the right one. Both provide me with very good solutions. And here I thought it would be impossible. Now, Strategy Pattern is not what I was looking for. To use Strategy, I'd have to implement the methods so I would be able to swap them.Tapdance
A
10

The easiest way to do it is probably DLINQ as TcKs suggested.

The fastest (I believe, in 3.5) is to create a DynamicMethod. Its also the scariest method as well. You're essentially building a method using IL, which has about the same feel as writing code in machine language.

I needed to do this to dynamically attach event handlers in some thing or another (well, I didn't need to do it, I just wanted to make unit testing events easier). It seemed a bit daunting at the time because I don't know crap about IL, but I figured out a simple way to accomplish this.

What you do is create a method that does exactly what you want. The more compact the better. I'd provide an example if I could figure out exactly what you're trying to do. You write this method in a class within a DLL project and compile it in release mode. Then you open the DLL in Reflector and disassemble your method. Reflector gives you the option of what language you wish to disassemble to--select IL. You now have the exact calls you need to add to your dynamic method. Just follow the example on MSDN, switching out the example's IL for your reflected methods' code.

Dynamic methods, once constructed, invoke at about the same speed as compiled methods (saw a test where dynamic methods could be called in ~20ms where reflection took over 200ms).

Anesthetize answered 3/7, 2009 at 16:47 Comment(2)
WoW, and here I thought I knew something about .NET. And I never heard of it. I am afraid of asking how did you ever manage to stumble upon such feature.Tapdance
DynamicMethod is available since 2.0Sharlenesharline
S
8

Your question is pretty unclear, but you can certainly use expression trees to create delegates dynamically at execution time. (There are other ways of doing it such as CodeDOM, but expression trees are handier if they do all you need. There are significant restrictions to what you can do, however.)

It's often easier to use a lambda expression with some captured variables though.

For example, to create a function which will add the specified amount to any integer, you could write:

static Func<int, int> CreateAdder(int amountToAdd)
{
    return x => x + amountToAdd;
}

...
var adder = CreateAdder(10);
Console.WriteLine(adder(5)); // Prints 15

If this doesn't help, please clarify your question.

Strategist answered 3/7, 2009 at 16:29 Comment(0)
S
7

Not that I am recommending this over the other better options, but there is a 7th method and thats to use AssemblyBuilder,ModuleBuilder,TypeBuilder, and MethodBuilder in the System.Reflection.Emit namespace to create a dynamic assembly. This is the same similar voodoo as using DynamicMethod.

For example you could use these to, at runtime, create a proxy class for a type and override virtual methods on that type.

To get you started here is some code...

using System;
using System.Reflection;
using System.Reflection.Emit;

var myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("Test"), AssemblyBuilderAccess.RunAndSave);
var myModule = myAssembly.DefineDynamicModule("Test.dll");
var myType = myModule.DefineType("ProxyType", TypeAttributes.Public | TypeAttributes.Class,
                        typeof(TypeToSeverelyModifyInAnUglyWayButItsNecessary));
var myMethod = myType.DefineMethod("MethodNameToOverride", 
                        MethodAttributes.HideBySig | MethodAttributes.Public,
                        typeof(void),Type.EmptyTypes);
var myIlGenerator = myMethod.GetILGenerator();
myIlGenerator.Emit(OpCodes.Ret);
var type = myType.CreateType();
Serb answered 3/7, 2009 at 18:1 Comment(2)
It seems to take about the same ammount of code to get done than simply using DynamicMethod. Is there any reason to use it over DynamicMethod? If Will is right, DynamicMethods are almost as fast as compiled code (even though 20ms is an eternity in computer time).Tapdance
The only real 'advantages' to using this over dynamic methods are that you can save the generated assembly and you can inherit from types and override virtual methods/properties. Hope this helps. Again, I am not recommending this for general consumption, just pointing out another option. When you said that you need to 'redefine' a method, depending on what you mean, this might be a better option since you can create a type and override base methods...Serb
Z
2

Use .net core 3.1, you can create dynamic method with IL language(mono is same as well):

using System.Linq.Expressions;
using System.Reflection.Emit;

class Program
{
    static void Main()
    {
        DynamicMethod hellomethod = new DynamicMethod("WriteLine", typeof(void), new[] { typeof(string) }, typeof(Program).Module);
        ILGenerator il = hellomethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
        il.Emit(OpCodes.Ret);
        Action<string> hello4 = (Action<string>)hellomethod.CreateDelegate(typeof(Action<string>));
        hello4("Hello World!");
    }
}
Zachariahzacharias answered 14/1, 2021 at 10:52 Comment(0)
E
0

If you declare the method as virtual, you might be able to use Castle's DynamicProxy to substitute a dynamically-generated (with one of the other answer's methods) implementation at runtime:

Castle DynamicProxy is a library for generating lightweight .NET proxies on the fly at runtime. Proxy objects allow calls to members of an object to be intercepted without modifying the code of the class. Both classes and interfaces can be proxied, however only virtual members can be intercepted.

Extortioner answered 3/7, 2009 at 18:18 Comment(2)
I tend to avoid using Third-Party libraries in my code. That's to avoid vendor lock-in problem. I've had serious problems with that previously when I coded in Delphi. In example, I have just switched from using SQLite - even though I like it very much - to SQLServer CE just to stay fully within the Framework.Tapdance
It does have the advantage of being open source, so you're not as "locked in" as you would be with a commercial solution. Sometimes you just have to weigh up the advantages of reinventing the wheel vs. actually getting things done.Extortioner
G
0

The second paragraph in your question suggests that really what you might be after is straightforward IOC (Inversion of Control)

Instead of declaring an instance of your class, you declare an instance of an interface and based on whatever condition you choose, you use the particular overriding class with the correct method in it. Hope that makes sense.

Grande answered 3/7, 2009 at 18:19 Comment(2)
No, it isn't. What I want is to be able to modify a method of a class during runtime to something I will be typing in runtime. Pretty much similar to an eval, except that I don't simply want it to eval and die. I want it to remain attached to a delegate until I need to change it again.Tapdance
Ah, ok, so your app might have a text input that lets you enter some code to modify the action of a function?Grande
C
0

You should check to see if your problem can be solved with simple polymorphism first. Unless you're defining abstract interoperability to another language or editing the compiler, trying to change a method at runtime is probably the wrong solution to the problem.

Corvine answered 3/7, 2009 at 19:30 Comment(1)
I Agree 100%, this should be the first choice.Serb

© 2022 - 2024 — McMap. All rights reserved.