如果我写这个:
public interface IOutModifier
{
void OutModifier(out int a);
}
尝试在接口中实现它,VS生成它(如预期的那样):
public class IOM : IOutModifier
{
public void OutModifier(out int a)
{
throw new NotImplementedException();
}
}
如果我写这个:
public interface IOutAndOutAttributeModifier
{
void OutAndOutAttributeModifier([Out] out int a);
}
VS会像这样实现它:
public class IOOAM : IOutAndOutAttributeModifier
{
public void OutAndOutAttributeModifier([Out]out int a)
{
throw new NotImplementedException();
}
}
旁注:写下这个:
public interface IOutAttributeModifier
{
void OutAttributeModifier([Out] int a);
}
将实现如下:
public class IOAM : IOutAttributeModifier
{
public void OutAttributeModifier([Out] int a)
{
throw new NotImplementedException();
}
}
所以,似乎有办法区分OutAttribute是否存在......但我无法弄清楚如何(通过Reflection)。在这两种情况下,任何获取自定义属性信息的方法(GetCustomAttributes(),GetCustomAttributeData()等)都会报告OutAttribute存在于所有接口方法中。这不是当前项目中存在代码的情况 - 如果我使用这些接口引用程序集,VS仍会生成上面显示的相同代码。
那么,我如何区分一个只是“out”的参数和一个明确添加了“[Out]”属性的参数呢?
答案 0 :(得分:1)
实际上你的两个代码都不一样。
IOM
正确使用输出参数。 IOAM
只是失败。
例如,尝试使用值而不是变量调用方法。它应该无法编译。因为传递给参数的out参数必须是变量而不是值。
IOM iom = new IOM();
iom.OutModifier(4);//Fails as expected
IOAM ioam = new IOAM();
ioam.OutAttributeModifier(4);//Compiles fine
这是因为out参数必须通过引用传递。在您的示例IOAM
中,您可以按值传递它。
IOM的MSIL代码是
.method public hidebysig newslot virtual final instance void OutModifier([out] int32& a) cil managed
IAOM的MSIL代码是
.method public hidebysig newslot virtual final instance void OutAttributeModifier([out] int32 a) cil managed
注意IAOM.OutAttributeModifier a
参数不通过引用传递。
我认为这是对你案件的疏忽。如果这是故意的,那么你可以通过检查ref是否传递参数来区分它。您可以致电ParameterInfo.ParameterType.IsByRef
。
答案 1 :(得分:0)
您正被一个C#特定功能绊倒,即方法参数上ref
和out
限定符之间的区别。区分对于实现definite assignment语言功能非常重要,对于检测未分配变量的使用非常有用。
问题是,CLR对此没有任何支持。它只能区分通过值(ParameterAttributes.In)或引用(ParameterAttributes.Out)传递参数。例如,与VB.NET ByVal
vs ByRef
关键字进行比较。
那么C#编译器如何知道在另一个程序集中编译的方法将参数传递为out
而不是ref
?它无法从ParameterAttributes中找到它根本不编码的区别。它无法确定其他程序集的源代码是否是用VB.NET编写的,这种语言没有相同的区别。
您可能通过尝试使用Reflection发现的内容知道答案。 C#编译器自动会在声明为[Out]
的任何参数上发出out
属性。如果该属性丢失,则会将其解释为ref
。
这是你可以用反编译器看到的东西,比如ildasm.exe:
.method public hidebysig newslot virtual final
instance void OutModifier([out] int32& a) cil managed
// etc...
注意[out]的存在。如果您将界面更改为ref
,则会变为:
.method public hidebysig newslot virtual final
instance void OutModifier(int32& a) cil managed
并注意[out]
现在如何丢失。因此实际上,在OutModifier()和OutAndOutAttributeModifier()实现方法之间没有任何区别,它们都在参数上使用[Out]
进行编译。正如反思告诉你的那样。
如果你需要这个区别,你肯定不在这个例子中,那么你需要用另一种语言编写方法,比如VB.NET。