2012-11-13 32 views
12

.NET 4 kullanarak, derleyicinin aşağıdaki örnekte ilk yöntem çağrısını çözümleyememesi nedeniyle kafam karıştı.Varsayılan parametreler ve jenerikler ile yöntem çözünürlüğü sorunu

using System; 

namespace MethodResolutionTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      NonGeneric foo = null; 

      // ambiguous 
      foo.Ext1(x => new NonGeneric()); 

      // resolves to first Ext1 
      foo.Ext1(x => new NonGeneric(), 1); 


      // resolves to first Ext2 
      foo.Ext2(x => new NonGeneric()); 

      // resolves to first Ext2 
      foo.Ext2(x => new NonGeneric(), 1); 

      // resolves to second Ext2 
      foo.Ext2(x => "foo"); 

      // resolves to second Ext2 
      foo.Ext2(x => "foo", 1); 


      // resolves to first Ext3 
      foo.Ext3(x => new NonGeneric()); 

      // resolves to first Ext3 
      foo.Ext3(x => new NonGeneric(), 1); 

      // resolves to second Ext3 
      foo.Ext3(x => "foo"); 

      // resolves to second Ext3 
      foo.Ext3(x => "foo", 1); 
     } 
    } 

    public class NonGeneric 
    { 
    } 

    public class Generic<T> : NonGeneric 
    { 
    } 

    public static class Extensions1 
    { 
     public static NonGeneric Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext1<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0, string s = null) 
     { 
      return null; 
     } 
    } 

    // only difference between Extensions2 and Extensions1 is that the second overload no longer has a default string parameter 
    public static class Extensions2 
    { 
     public static NonGeneric Ext2(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext2<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0) 
     { 
      return null; 
     } 
    } 

    // Extensions3 explicitly defines an overload that does not default the int parameter 
    public static class Extensions3 
    { 
     public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext) 
     { 
      return Ext3(first, getNext, default(int)); 
     } 

     public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext3<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0) 
     { 
      return null; 
     } 
    } 
} 

Bu konuda biraz ışık tutabilir mi? Derlememde yardımcı olmak için API'larımı değiştirmekten başka bir yolum olmadığından şüpheliyim (yukarıdaki Extensions3'a göre), ancak daha kolay/daha iyi bir yol varsa bunu duymak isterim.

cevap

1

Bu, ikinci Ext1 uzantı yönteminde iki isteğe bağlı parametreye sahip olduğunuzdan belirsizdir. İlk aramada her iki parametre de ihmal edildiğinden, derleyici kullanmak istediğinizi bilmiyor. C# 4.0 Language Specification itibaren

:

§7.5.3 Aşırı çözünürlük:

uygulanabilir aday fonksiyonu üyelerinin verilmesi durumunda, bu sette iyi işlev üyesi bulunmaktadır. Sette sadece bir fonksiyon elemanı varsa, o fonksiyon elemanı en iyi fonksiyon üyesidir. Aksi takdirde, en iyi işlev üyesi, her işlev üyesinin §7.5.3.2'deki kuralları kullanan diğer tüm işlev üyeleriyle karşılaştırılması koşuluyla, belirtilen işlev listesiyle ilgili olarak diğer tüm işlev üyelerinden daha iyi olan bir işlev üyedir. Diğer tüm işlev üyelerinden daha iyi bir işlev üyesi yoksa, işlev üyesi çağırma belirsizdir ve bir bağlama zamanı hatası oluşur. Ayrıca

,
§7.5.3.2 iyi işlev üyesi altında: parametre listesinden

kaldırılır hiçbir karşılık gelen argümanlarla

İsteğe bağlı parametreler Bunun anlamı olduğunda sizi o yöntem çağrısında en son iki argümanı atlayın ve NonGeneric türünün çıkarıldığı (§7.5.2 altındaki tür çıkarımını okuyun), her iki yöntem şöyle görünecektir:

Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext) 

Böylece onlar

Ben §7.5.3.2 veya daha fazla bilgi için şartname hatta tüm §7.5.3 okuma öneriyoruz ... belirsiz olacaktır.

çözüm bu değil bu yüzden, işi :) derleyici `Extensions2` ve` Extensions3` senaryolarda hem de ince seçer

+0

yapmak ikincisini senin yöntem bildirimlerini değiştirmek veya tamamen birinci aşırı kaldırmak ve izin ya olduğu bu kadar basit. Ayrıca, eğer varsayılan 'int' parametresini istemediysem, o zaman ilk etapta bu şekilde ilan edemezdim! –

+0

Ancak, isteğe bağlı parametreler atlanırsa neden etkin bir şekilde belirsiz olan isteğe bağlı parametrelerle iki yönteminiz var? Her iki yönteme de mutlaka ** ihtiyacınız varsa, 'Extensions2' veya' Extensions3' çözümlerinizi kullanmanız gerekir. – khellang

+0

@khellang: Böyle bir davranışa yol açan C# dil özellikleri bölümlerini işaret edebilir misiniz (aşırı çözünürlük belirsizliği)? –