Sunny、ref 和 out 是编译器的编组提示 + 合同。Ref 和 out 是 COM 日的遗留物——当通过线路/进程之间发送时对象的编组提示。
out
合同_
void foo( out MyClass x)
- foo() 将
x
在返回之前设置为某个值。
x
输入 foo() 时没有值,如果x
在设置之前尝试使用,则会出现编译器错误。(使用未分配的输出参数 x)
ref
合同_
void foo( ref MyClass x)
- ref 允许更改调用者引用。
- x 必须是可分配的
- 您不能将某些东西转换为中间变量 foo( ref (object) something)
- x 不能是属性
最后两点的现实可能会阻止您做您想做的事情,因为实际上当您了解参考的真正含义时,它们毫无意义。如果您想知道这一点,请询问 Jon Skeet(他写了一本书)。
在编组 ref 时,它表示除了返回值之外,还要带回 ref 值。编组时,它说在调用方法时不要费心发送输出值,但请记住除了返回值之外还要带回输出值。
免责声明 免责声明
正如其他人指出的那样,正在发生一些可疑的事情。您维护的蛮力代码似乎有一些微妙的错误,并且由于巧合而受到编码的影响。最好的解决方案可能是添加另一层间接。即包装器类的包装器,可确保确定性清理,您可以在其中编写一次且仅一次的凌乱代码,而不是将其散布在整个代码库中。
那说..
备选方案 1
除非您为将调用它的每种类型的 (com) 对象提供重载,否则 Ref 不会起作用。
// need a remove method for each type.
void Remove( ref Com1 x ) { ...; x = null; }
void Remove( ref Con2 x ) { ...; x = null; }
void Remove( ref Com3 x ) { ...; x = null; }
// a generics version using ref.
void RemoveComRef<ComT>(ref ComT t) where ComT : class
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(t);
t = null;
}
Com1 c1 = new Com1();
Com2 c2 = new Com2();
Remove( ref c1 );
RemoveComRef(ref c2); // the generics version again.
备选方案 2
如果您不想这样做,请从 Remove() 方法返回 null 并转换回对象的类型。
class Remover
{
// .net 1.1 must cast if assigning
public static object Remove(object x)
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(x);
return null;
}
// uses generics.
public static ComT RemoveCom<ComT>(ComT t) where ComT : class
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(t);
return null;
}
}
Com1 c1 = new Com1();
Com2 c2 = new Com2();
c1 = (Com1)Remover.Remove(c1); // no reliance on generics
c2 = Remover.RemoveCom(c2); // relies on generics
* 我添加了通用版本进行比较。
上面的代码的效果是,在查看代码时,当您看到对 Remove(x) 的调用而没有赋值时会变得可疑(使错误的代码看起来是错误的)。您甚至可以通过代码库 Grep 查找未进行分配的 Remove 调用。
免责声明-以上所有内容都基于您需要手动将引用设置为 null ,这(通常)不是必需的。