我不知道如何正确地说这个,所以请耐心等待。在C#.NET中工作,我继承了一个类,该类包含一个返回非托管函数对象的函数。当我直接使用继承的函数时,非托管任务失败。如果我创建对继承函数返回的对象的引用,并从引用的对象中调用非托管函数,则它可以工作。
伪.NET代码示例:
public class A {
void UnmanagedFunc() {...}
}
public class B {
public A GetA() {
return new A();
}
}
public class C : B {
public void DoSomething() {
this.GetA().UnmanagedFunc();
}
}
public class D : B {
public void DoSomething() {
var a = this.GetA();
a.UnmanagedFunc();
}
}
您可以看到C类和D类中的函数是等价的,但D声明了对基类函数实例化的对象的引用。
我的同事说声明变量会让非托管进程有时间完成,因为变量的对象仍然需要处理直接访问对象的位置。
这有点道理,但我觉得这不是一个令人满意的答案。
任何人都可以解释这种现象吗?
答案 0 :(得分:4)
如果我理解你的问题,你想知道为什么:
this.GetA().UnmanagedFunc();
失败了,而这个:
var a = this.GetA(); a.UnmanagedFunc();
没有。
好吧,让我这样说:至少在非调试版本中,允许编译器和运行时(特别是JIT代码生成器)应用优化,可能只是优化局部变量a
因此,您应该为所有实际目的假设您的代码的两个版本在功能上相同。
在你给出的这么简单的例子中,局部变量只有一个优点:它为你提供了“命名”或描述GetA()
返回的对象的方法;例如,您可以调用局部变量aForFrobbling
,lastUsedA
或其他任何内容。
“我的同事说声明变量会让非托管的处理时间完成,因为变量的对象仍然需要处理直接访问的对象所在的位置。”
我不接受这个论点,主要是因为看起来你的同事对.NET内存管理有一些错误的想法。
不是变量被处置,而是对象不再被所述变量(或其他任何东西,如字段或参数)引用。
.NET中的垃圾收集(GC)是不确定的。仅仅因为变量超出范围并不意味着它最后引用的对象立即被回收。对象(至少是堆上的对象)至少在下一个GC运行时(无论何时)运行;它们是否被变量/字段/参数引用。导致对象被回收的唯一原因是它不再被任何东西引用;但你不知道什么时候GC会启动(除非你明确触发它)。
术语:.NET中的“Disposal”强烈建议所讨论的对象是一种实现IDisposable
的类型。从您的代码示例来看,这似乎不是这种情况。
话虽如此,也许我们看不到所有相关的代码。哪里有“处置”?您的非托管代码是否继续在后台运行(即在单独的线程中)并对.NET垃圾收集器无法了解的.NET对象执行操作?无论如何,非托管函数(UnmanagedFunc
)如何成为托管对象的方法?许多问题。除了我上面所说的,我觉得我无法完全回答你的问题。
一件事:如果你需要在处理对象之前给出一些非托管代码时间,那么你应该重新考虑你的程序的设计。使时间显式,不要依赖有时只能工作的技巧(即使这样,你也不知道为什么):非托管代码应该为你提供询问它是否完成的方法;无论是通过回调函数还是某些事件机制。如果是这样,请确保在此之前通过扩展其生命周期范围(例如通过将对象存储在类字段而不是局部变量中)来释放.NET对象。或查看System.Runtime.InteropServices.Marshal
课程为您提供的各种可能性。