Invoke yöntemini kullandığımda derleme TAMAM, neden Func <int, int> döndürdüğümde TAMAM değil?


28

Bu davayı anlamıyorum:

public delegate int test(int i);

public test Success()
{
    Func<int, int> f = x => x;
    return f.Invoke; // <- code successfully compiled 
}

public test Fail()
{
    Func<int, int> f = x => x;
    return f; // <- code doesn't compile
}

InvokeYöntemi kullandığımda derleme neden TAMAM, csharp Func<int,int>doğrudan döndüğümde TAMAM değil ?


Bir temsilciniz var, bu da bir çeşit etkinlik alacağınız anlamına geliyor. Çağırma, çapraz iş parçacığı istisnasını önler ve birden çok işlemin nesneye erişmesine izin verir.
jdweng

Eğer gibi iki özdeş-görünüşteki delegeleri kullansalar bile bu sorunu göreceği Not delegate void test1(int i);vedelegate void test2(int i);
Matthew Watson

Yanıtlar:


27

Bu davranışı anlamak için bilmeniz gereken iki şey var.

  1. Tüm delegeler türetilir System.Delegate, ancak farklı delegelerin farklı türleri vardır ve bu nedenle birbirlerine atanamazlar.
  2. C # dili , bir temsilciye bir yöntem veya lambda atamak için özel işlem sağlar .

Farklı delegelerin farklı türleri olduğundan, bu, bir türden başka bir delege atayamayacağınız anlamına gelir.

Örneğin, verilenler:

delegate void test1(int i);
delegate void test2(int i);

Sonra:

test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a;                 // Using normal assignment, therefore does not compile.

Yukarıdaki ilk satır, bir delege için lambda veya yöntem atamak için özel işlemeyi kullandığından, Tamam derler.

Aslında, bu satır derleyici tarafından etkili bir şekilde yeniden yazılır:

test1 a = new test1(Console.WriteLine);

Yukarıdaki ikinci satır derlenmez, çünkü bir türden bir örneği başka bir uyumsuz türe atamaya çalışmaktadır.

Tiplere göre , farklı tipler olduğu için test1ve test2bunlar arasında uyumlu bir atama yoktur .

Düşünmeye yardımcı oluyorsa, bu sınıf hiyerarşisini düşünün:

class Base
{
}

class Test1 : Base
{
}

class Test2 : Base
{
}

Aşağıdaki kod derlemek, olsa ETMEYECEKTIR Test1ve Test2aynı temel sınıf türetmek:

Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.

Bu, neden bir temsilci türünü diğerine atayamayacağınızı açıklar. Bu sadece normal C # dili.

Ancak, önemli olan, uyumlu bir delege için neden bir yöntem veya lambda atamanıza izin verildiğini anlamaktır. Yukarıda belirtildiği gibi, bu delegeler için C # dil desteğinin bir parçasıdır.

Sonunda sorunuzu cevaplamak için:

Kullandığınızda Invoke(), uyumlu olmayan bir tür atamaya çalışmak yerine bir temsilciye yöntem veya lambdas atamak için özel C # dil işlemeyi kullanarak temsilciye bir METHOD çağrısı ataıyorsunuz - bu nedenle Tamam derliyor.

Tamamen açık olmak gerekirse, OP'nizde derleyen kod:

public test Success()
{
    Func<int, int> f = x => x;
    return f.Invoke; // <- code successfully compiled 
}

Aslında kavramsal olarak şuna dönüştürülür:

public test Success()
{
    Func<int, int> f = x => x;
    return new test(f.Invoke);
}

Başarısız olan kod iki uyumsuz tür arasında atamaya çalışırken:

public test Fail()
{
    Func<int, int> f = x => x;
    return f; // Attempting to assign one delegate type to another: Fails
}

6

İkinci durumda, ftürdür Func<int, int>, ancak yöntemin a döndürdüğü söylenir test. Bunlar birbiriyle dönüştürülemeyen ilişkisiz (delege) türlerdir, bu nedenle bir derleyici hatası oluşur. Dil spesifikasyonunun bu bölümüne gidip "delege" için arama yapabilirsiniz. Aynı imzaya sahip delegeler arasındaki dönüşümlerden bahsedilmez.

Ancak ilk durumda, aslında bir türü olmayan f.Invokebir yöntem grubu ifadesidir . C # derleyicisi bir yöntem grubu dönüşümü yoluyla yöntem grubu ifadelerini bağlama göre belirli delege türlerine dönüştürür .

( Burada 5. mermiden alıntı, benimkini vurgula)

Bir ifade aşağıdakilerden biri olarak sınıflandırılır:

  • ...

  • Bir üye aramasından kaynaklanan aşırı yüklenmiş yöntemlerden oluşan bir yöntem grubu. [...] Bir yöntem grubuna invocation_expression, delegate_creation_expression ve isoperatörün sol tarafı olarak izin verilir ve dolaylı olarak uyumlu bir delege tipine dönüştürülebilir.

Bu durumda, testdelege türüne dönüştürülür .

Başka bir deyişle, return fçünkü çalışmaz fzaten bir tür vardır, ancak f.Invokehenüz bir türüne sahip değil.


2

Burada sorun Tür uyumluluğu:

MSDN Kaynakları'ndan Func delege tanımı aşağıdadır :

public delegate TResult Func<in T, out TResult>(T arg);

Yukarıda belirtilen Func ile tanımladığınız Temsilci arasında doğrudan bir ilişki görmüyorsanız:

public delegate int test(int i);

İlk snippet neden derlenir:

public test Success()
{
    Func<int, int> f = x => x;
    return f.Invoke; // <- code successfully compiled 
 }

Delegeler, giriş parametreleri ve Çıktı sonucu olan imza kullanılarak karşılaştırılır, sonuçta bir Delege bir İşlev işaretçisi olur ve iki işlev yalnızca imza ile karşılaştırılabilir. Çalışma zamanında Func üzerinden çağrılan yöntem Testdelege için atanır , İmza aynı olduğundan sorunsuz çalışır. Bu, bir işlev işaretçisi atamasıdır; burada Testdelege Func delegesi tarafından gösterilen yöntemi çağıracaktır.

2. Snippet neden derlenemiyor

Func ve test temsilcisi arasında tür / atama uyumluluğu yoktur, Func Tür sistem kurallarının bir parçası olarak dolduramaz. Sonuç test delegateilk durumda olduğu gibi atanıp doldurulabilse bile .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.