2015-09-09 42 views
11

Şu anda C# içinde varoluşsal türleri kullanarak çözülebileceğini düşündüğüm bir sorunla karşı karşıyayım. Ancak, C# 'da yaratılıp yaratılamayacaklarını ya da simüle edildiklerini (başka bir yapı kullanarak) gerçekten bilmiyorum. Ama neler tür parametresi önemsemedenVarolan türleri C#?

public interface MyInterface<T> 
{ 
    T GetSomething(); 
    void DoSomething(T something); 
} 

public class MyIntClass : MyInterface<int> 
{ 
    int GetSomething() 
    { 
     return 42; 
    } 

    void DoSomething(int something) 
    { 
     Console.Write(something); 
    } 
} 

public class MyStringClass : MyInterface<string> 
{ 
    string GetSomething() 
    { 
     return "Something"; 
    } 

    void DoSomething(string something) 
    { 
     SomeStaticClass.DoSomethingWithString(something); 
    } 
} 

İleri Bu arabirim uygulamak nesneler listesi üzerinden yineleme edebilmek istiyorum:

Temelde bu gibi bazı kod sahip olmak istiyorum. Böyle bir şey:

public static void DoALotOfThingsTwice(){ 
    var listOfThings = new List<MyInterface<T>>(){ 
     new MyIntClass(), 
     new MyStringClass(); 
    }; 

    foreach (MyInterface<T> thingDoer in listOfThings){ 
     T something = thingDoer.GetSomething(); 
     thingDoer.DoSomething(something); 
     thingDoer.DoSomething(something); 
    } 
} 

MyIntClass kullandığı T ve MyStringClass tarafından kullanılan bir farklı olduğu için bu derleme değil.

Böyle bir şey hile yapabileceğini düşünüyordum, ama C# bunu geçerli bir yol varsa ben bilmiyorum:

public static void DoALotOfThingsTwice(){ 
    var listOfThings = new List<∃T.MyInterface<T>>(){ 
     new MyIntClass(), 
     new MyStringClass(); 
    }; 

    foreach (∃T.MyInterface<T> thingDoer in listOfThings){ 
     T something = thingDoer.GetSomething(); 
     thingDoer.DoSomething(something); 
     thingDoer.DoSomething(something); 
    } 
} 
+2

gibi, hayır, bu mümkün değil: Şimdilik

, bunun olası çözüm olması gerektiğine inanıyoruz. – Servy

+2

İşlemi bir 'Eylem 'içine sarın ve ardından bunları bir listede saklayabilirsiniz. Bu eylemleri genel olarak oluşturabilirsiniz. – Lee

cevap

5

DoALotOfThingsTwice, T numaralı telefondan beri bir Action numaralı telefona bağlanarak listeye bunları kaydedebilirsiniz, örn. Sonra

var listOfThings = new List<Action>() { 
    new MyIntClass().DoSomethingTwice(), 
    new MyStringClass().DoSomethingTwice() 
}; 
+0

Bu sadece bu listede bazı ek işler yapabilsem çalışırdı, değil mi? Örneğin, 'DoSomethingTwice' bir değer döndürdüğünde, 'Func '(bazı' X' tipi için)' yaparsa, o zaman 'X' değerlerini (her bir işlevi değerlendirdikten sonra) kullanarak listede çalışmama izin verir. Ama eğer 'DoSomethingTwice' dışında başka bir şey yapmazsam, o zaman listeyi kullanmadan, her nesnede ayrı ayrı 'DoSomethingTwice' olarak adlandırmak aynı olurdu. – gonzaw

+0

@gonzaw - 'foreach' döngüsünde her bir öğe üzerinde ayrı ayrı 'DoSomethingTwice' diyemezsiniz, çünkü ilk önce istediğiniz listeyi oluşturamazsınız. 'T' üzerinden soyutlayabileceğiniz noktada bir tür sarıcı yapmalısınız. Eğer 'foreach' döngüsünde kullanılmak üzere bir "T" değeri döndürmeniz gerekiyorsa, o zaman aynı soruna sahip olursunuz, çünkü C#, varoluşsal türleri istediğiniz gibi desteklemediğinden beri "T" yi tanımlayamazsınız. Bununla birlikte, döngü içinde her bir T ile ne yaparsınız? “T” yi bilmeden bir şey yapamazsın. – Lee

3

Değil mümkün doğrudan C#.

yapabilirsiniz damla tip emniyet ve ya olmayan jenerik baz arayüze sahip ve "jenerik" kodunu kullanmak:

public interface MyInterface 
{ 
    object GetSomething(); 
    void DoSomething(object something); 
} 

public interface MyInterface<T> : MyInterface 
{ 
    T GetSomething(); 
    void DoSomething(T something); 
} 

Veya kullanmak dynamic (yine hiçbir derleme zamanı tür güvenliği):

foreach (dynamic thingDoer in listOfThings) 
{ 
    dynamic something = thingDoer.GetSomething(); 
    thingDoer.DoSomething(something); 
    thingDoer.DoSomething(something); 
} 

Veya işleyicinin birden çok sürümünü oluşturur ve (büyük olasılıkla önbelleğe alma ile) türünü (How do I use reflection to call a generic method?) temel alarak oluşturun (Not: List<object> veya List<NonGenericBaseInterface> veya'den daha iyi "keyfi nesneler listesi" ni ifade edemezsiniz): yansıması

foreach (object thingDoer in listOfThings) 
{ 
    // get Do via reflection and create specific version based on 
    // thingDoer.GetType(), than invoke 
    // consider caching "methodForType" in Dictionary by type 
    MethodInfo method = this.GetType().GetMethod("Do"); 
    MethodInfo methodForType = method.MakeGenericMethod(thingDoer.GetType()); 
    methodForType.Invoke(thingDoer, null); 

} 

void Do<T>(MyInterface<T> thingDoer) 
{ 
    T something = thingDoer.GetSomething(); 
    thingDoer.DoSomething(something); 
    thingDoer.DoSomething(something); 
} 

Alternatif benzer bir kod oluşturmak için İfade ağacı kullanmaktır.

+0

Bu yaklaşımlardan hangisi onu LINQ ile entegre etmeme izin verir? Örneğin, "genel" kodu bir fonksiyona taşıyacak olursak, genel statik geçersiz DoSomethingTwice (MyInterface thingDoer) ', yaklaşımlarınızdan biri onu' listOfthings.Select (DoSomethingTwice) 'kullanarak eşleştirmeme izin verir mi? 'Object' ı kullanarak yaklaşmak bunun için çalışacak gibi görünüyor, değil mi? – gonzaw

+0

@gonzaw evet, genel olmayan arabirim bazı tür güvenlik ('List ') ve linq 'listOfthings.Select (DoSomethingTwice)' işlevini kullanır, ancak eleman türünde gönderme yapmaz - bu nedenle 'DoSomethingTwice' olurdu her tür için çalışmak veya kodda tür üzerinde sevk yapmak. –

1

Ben kurşun geçirmez bir çözüm sağlayamaz gerçek alan içinde yatan mesele bilmiyorum yana

public static Action DoSomethingTwice<T>(this MyInterface<T> i) 
{ 
    return() => 
    { 
     T something = i.GetSomething(); 
     i.DoSomething(something); 
     i.DoSomething(something); 
    }; 
} 

. what's covariance and contravariance in generic parameters both on interfaces and delegates'a bakmanız gereken çabaya değmeli ve bu yaklaşımı kodunuzu yeniden denemeye çalışın. tipi değişmez olduğu

public static void DoALotOfThingsTwice() 
{ 
    var listOfThings = new List<object> 
    { 
     new MyIntClass(), new MyStringClass() 
    }; 

    MyInterface<int> a; 
    MyInterface<string> b; 

    // During each iteration, check if the thing is a concrete 
    // implementation of your interface MyInterface<T>... 
    foreach (object thingDoer in listOfThings) 
    {   
     // ...and call MyInterface<T>.DoSomething method depending on 
     // the success of the cast to MyInterface<int> or 
     // MyInterface<string> 
     if ((a = thingDoer as MyInterface<int>) != null) 
      a.DoSomething(38); 
     else if((b = thingDoer as MyInterface<string>) != null) 
      b.DoSomething("hello world"); 
    } 
}