问题描述
我需要能够在 C# 中使用 Mono 调用基于函数指针的单个方法.委托为此工作得很好,这是他们的目的,但他们似乎每次我设置委托时分配 52 个字节(不是 +=,而是使用 = 设置它,所以委托引用的方法总是一个且只有一个).
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).
此委托每秒更改多次,它会导致 GC 定期启动,我希望避免这种情况.
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?
如果没有,除了每次更改地址时不会分配任何内存的委托之外,还有其他动态方式来调用 C# 中的方法吗?
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?
推荐答案
任何代码都这样写
Action action = foo.DoSomething;
最终被编译成这个
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;
缓存修复
另一种选择是使用某种缓存类,但这会引入一大堆对象生命周期问题,您可能不希望在游戏场景中出现这些问题.这是一个有点粗略的实现,真正的人可能想要使用弱引用.
Cache Fix
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;
}
}
使用它看起来像这样
Action action = DelegateCache.GetDelegate<Action>(foo, "DoSomething");
总结
运行一些测试,这两种方法对于每个对象/方法对只有一个分配.我可能会去实施方面修复它,尽管它需要做很多工作,但它会更干净.如果有很多方法,并且您计划添加更多方法,则可以使用 T4 生成一个部分类,其中包含方法的委托实现.
Summary
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.
这篇关于分配免费委托或其他按地址调用方法的方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!