Neden 'Out BaseClass'dan' Out DerivedClass'a dönüşemiyorum?
Bir outparametrenin türü olarak genel bir argümana sahip olmanın, bu genel türü değişmez olmaya zorladığını öğrendim . Bu benim için şaşırtıcı. outParametrelerin dönüş türleriyle aynı şekilde ele alındığını düşündüm (yani, genel parametre eşdeğişken ise, o zaman bir outçıkış parametresi olarak kullanılabilir ), çünkü her ikisi de bir yöntemin "çıktıları".
Biraz araştırdıktan sonra, bunu yapamayacağınızı anladım:
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;
}
}
Bu, outparametrelerin neden değişmez olması gerektiğini açıklar . Ancak, bunu neden yapamayacağınızı hala anlamıyorum. Yaygın olarak bilindiği gibi, outparametreler bir değeri döndürmenin başka bir yoludur. Fbir dönüş değeri ile yeniden yazılabilir ve çalışacaktır:
// 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;
}
}
Öyleyse neden ilk kod parçacığı derlenmiyor? Kullanmak , dönüş değerleri ile yapılamayacak bir şeyi yapmaya outizin verir mi, ona Fbir out object sgeçirilirse tür güvenliğini bozar mı?
Türetilmiş bir sınıftan temel sınıfa dönüştürmenin tam tersi olan bu soruyu buldum ki bu kesinlikle mümkün değil. Bir objecttürün değişkenine a döndüren bir yöntemin dönüş değerini atayamazsınız, değil stringmi?
Sormak istediğim, stringbir tür değişkenine dönen bir yöntemin dönüş değerini atayabildiğinize göre object, neden aynısını outparametrelerle yapamıyorsunuz ? Yani, neden out objectbir out stringparametreye geçemiyorsunuz ?
Ben de okumak belgeler ve spec ama asla bir içine tam olarak aynı tip geçmek zorunda olduğu gerçeği hiç söz outparametre şöyle dursun açıklamak bunu yapmak zorunda neden.
Yanıtlar
İle outparametrelerin argüman gibi referans olarak geçirilen reffark değeri yönteminin sonuna kadar atanmalıdır ve referans çağırmadan önce başlatılması gerekir olmamasıdır. Ancak daha önce başlatılabilir ve yöntem başlangıç değerini okuyabilir .
Dokümanlardan: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier
Out anahtar sözcüğü argümanların başvuru ile iletilmesine neden olur
Ref, değişkenin geçmeden önce başlatılmasını gerektirmesi dışında ref anahtar kelimesi gibidir.
Yöntem değişkeni okuyabildiğinden, referansın stringçalışacak türde olması gerekir . Okuma kovaryansı ve çıkış kontraveriği bloke eder, bu nedenle argüman değişmez olmalıdır.
Yaygın olarak bilindiği gibi, out parametreleri bir değeri döndürmenin başka bir yoludur
Doğru değil: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out
Bir parametre değiştirici olarak, bir argümanı değere göre değil, başvuruya göre bir yönteme iletmenize olanak tanır.
Bu, belirli bir nesneye bir referansı ilettiğiniz anlamına gelir.
Sanırım cevabın burada: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref
Başvuru türünün başvuruya göre iletilmesi, çağrılan yöntemin, başvuruda referans parametresinin başvuruda bulunduğu nesneyi değiştirmesini sağlar.
Yani işleve bir nesne ilettiğinizde, etkin bir şekilde bir tür ataması yapıyorsunuz
türetilmiş <- taban
ve işlevin içinden atarken
taban <- türetilmiş
C # 'da böyle bir şey yapabileceğinizi düşünün:
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();
Değişmek üzere yasal değilse string striçin object str, şimdi strnasıl Out ve Referans yöntemiyle arasındaki referansı tutmak için her türlü olabilir?