I need to be able to call a single method based on a function pointer in C# using Mono. Delegates work fine for this and it's their purpose, but they seem to allocate 52 bytes each time I set the delegate (not +=, but just setting it using = so there's always one and only one method referenced by the delegate).
This delegate changes many times per second and it causes the GC to kick in periodically which I'd like to avoid.
I don't mind the initial memory allocation, but is there a way to prevent an allocation each time I change the single delegate value?
If not, is there any other dynamic way to call a method in C# besides delegates that wouldn't allocate any memory each time the address is changed?
Only one method can be called using a delegate.
using System; delegate int MyDelegate(int a,int b);
A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.
If you think of delegates as being similar to interface definitions for a specific type of method, you can start to see why delegates exist. They allow clients of our delegates to ignore all the details of their implementations - even their names!
Any code you write like this
Action action = foo.DoSomething;
Ends up being compiled into this
Action action = new Action(foo.DoSomething);
Which is where the allocations are coming from. There aren't any perfect ways around this but to prevent the allocations you need to cache and reuse the delegate.
You could achieve this on the implementation side by creating a delegate for each of your methods.
public class Foo
{
public void DoSomething() { /*nop*/ }
private Action _doSomethingDelegate;
public Action DoSomethingDelegate
{
get { return _doSomethingDelegate ?? (_doSomethingDelegate = DoSomething); }
}
}
Then you would just reference the existing delegate rather than the method
Action action = foo.DoSomethingDelegate;
Another option is to use some sort of cache class but this introduces a whole pile of object lifetime issues which you probably don't want in a game scenario. This is a bit of a crude implementation are real one would probably want to use weak references.
public static class DelegateCache
{
private static readonly Dictionary<object, Dictionary<string, Delegate>> Cache = new Dictionary<object, Dictionary<string, Delegate>>();
private static Dictionary<string, Delegate> GetObjectCache(object instance)
{
Dictionary<string, Delegate> delegates;
if (!Cache.TryGetValue(instance, out delegates))
{
Cache[instance] = delegates = new Dictionary<string, Delegate>();
}
return delegates;
}
public static T GetDelegate<T>(object instance, string method)
where T: class
{
var delegates = GetObjectCache(instance);
Delegate del;
if (!delegates.TryGetValue(method, out del))
{
delegates[method] = del = Delegate.CreateDelegate(typeof(T), instance, method);
}
return del as T;
}
}
Using this would then look like this
Action action = DelegateCache.GetDelegate<Action>(foo, "DoSomething");
Running some tests both these methods have only a single allocation per object/method pair. I would probably go the implementation side fix it is a lot cleaner even though it is a lot of work. If there are a lot of methods and you plan on adding many more you could use T4 to generate a partial class with the delegate implementation for your methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With