问题描述
我刚刚了解到,将通用参数用作out
参数的类型会强制该通用类型保持不变。这令我惊讶。我认为out
参数与返回类型相同(即,如果通用参数是协变的,则可以将其用作out
out参数),因为它们都是a的“输出”方法。
经过一番调查,我意识到您不能这样做:
public class Program {
public static void Main() {
// cannot convert from 'out object' to 'out string'
F(out object s); // passing an out object
}
public static void F(out string o) {
o = null;
}
}
这说明了为什么out
参数必须不变。但是,我仍然不明白为什么您不能这样做。众所周知,out
参数只是返回值的另一种方法。可以用返回值重写F
,它将起作用:
// This is the semantically equivalent version of the above,just without "out"
public class Program {
public static void Main() {
object s = F();
}
public static string F() {
return null;
}
}
那么为什么第一个代码段不编译?使用out
是否允许F
执行返回值无法完成的操作,如果将out object s
传递给返回值,则会破坏类型安全性?
我发现this question,这是关于另一种方式的转换-从派生类转换为基类,这显然是不可能的。您不能将返回object
的方法的返回值分配给类型为string
的变量,可以吗?
我要问的是,因为您可以将返回string
的方法的返回值分配给类型object
的变量,所以为什么不能对{{1 }}参数?也就是说,为什么不能将out
传递给out object
参数?
我也阅读了docs和spec,但他们从未提及必须将完全相同的类型传递给out string
参数这一事实,更不用说解释为什么必须这样做。
解决方法
使用out
参数,该参数像引用ref
一样通过引用传递,不同之处在于该值必须在方法末尾赋值,并且在调用之前不需要初始化引用。但这可以在之前初始化,并且方法可以读取初始值。
从文档中:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier
out关键字导致参数通过引用传递
类似于ref关键字,除了ref要求在传递变量之前先对其进行初始化
由于该方法可以读取变量,因此引用必须为string
类型才能起作用。读取块具有协方差,输出块具有协方差,因此参数必须是不变的。
众所周知,out参数只是返回值的另一种方式
不正确:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out
作为参数修饰符,它使您可以通过引用而不是通过值将参数传递给方法。
这意味着您正在传递对特定对象的引用。
我想您的答案在这里:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref
通过引用传递引用类型可以使被调用方法替换调用者中引用参数所引用的对象。
因此,当您将对象传递给函数时,您实际上是在进行类型的分配
派生
以及从函数内部进行分配时
基本
,考虑一下,您可以在c#中执行以下操作:
public static void Out(out string s)
{
Thread.Sleep(50);
s = "World";
}
public static void Ref(ref string s)
{
Console.WriteLine(s); // Hello
Thread.Sleep(100);
Console.WriteLine(s); // World
}
string str = "Hello";
new Thread(() => Out(out str)).Start();
new Thread(() => Ref(ref str)).Start();
如果将string str
更改为object str
是合法的,那么现在str
可以是任何类型,如何在Out和Ref方法之间保留引用?