2010-05-03 15 views
12

this Java question ile benzer şekilde. Bir değişkenin birden çok arabirimi uyguladığını belirtmek isterim. Mesela.Net'te birden çok arabirimi uygulayan bir değişken bildirmenin bir yolu var mı?

için
private {IFirstInterface, ISecondInterface} _foo; 

public void SetFoo({IFirstInterface, ISecondInterface} value) 
{ 
    _foo = value; 
} 

Gereksinimler:

  • Ben Foo geçirilen olacağını en tipine bir arabirim ekleme olanağı yoktur. Bu yüzden IFirstInterface ve ISecondInterface'den gelen üçüncü bir arabirim oluşturamıyorum.
  • Mümkünse sınıf sınıfını jenerik yapmaktan kaçınmak isterim çünkü Foo'nun türü sınıfla çok ilgili değildir ve kullanıcı derleme zamanında bunu bilmez.
  • Daha sonra her iki arabirimdeki yöntemlere erişmek için foo kullanmam gerekir.
  • Bunu bir derleyici güvenli bir şekilde yapmak istiyorum, yani kullanmaya çalışmadan hemen önce arabirime yayınlamaya çalışıyorum. Eğer foo her iki arabirimi de uygulamazsa, oldukça fazla işlevsellik düzgün çalışmayacaktır.

Bu mümkün mü?

Edit: Bunu çeşitli nedenlerden dolayı birkaç kez istemiştim. Bu durumda, bir özellik kümesini ObservableCollections - ReadOnlyObservableCollections olarak değiştirdiğim için. ObservableCollection kaynağından başka bir Koleksiyona bir projeksiyon oluşturan bir yardımcı sınıfım var. ReadOnlyObservableCollection, ObservableCollection öğesinden devralmadığı için ve yalnızca IList ve INotifyCollectionChanged'de işlemlere ihtiyacım olduğundan, kaynak koleksiyonumu bir ObservableCollection gerektirmek yerine bu iki arabirimin bir bileşimi olarak kaydetmeyi umuyordum.

+1

Şansın bulunmaktadır. – ChaosPandion

+2

Kısa cevap: hayır. IFirstInterface ve ISecondInterface'den gelen üçüncü bir arabirimi tanımlamadan değil. – Anthony

+2

Tek düşüncem, aynı örneği iki arayüz değişkenine sahip olabilir miydiniz? Hangi durumda buna ihtiyacınız var? Böyle bir şeye ihtiyacın olduğu yerde ne yaptığına dair biraz bilgi verebilir misin? –

cevap

13

, o zaman şans şunlardır: Bu noktadan itibaren

public void SetFoo<T>(T value) where T : IFirstInterface, ISecondInterface 
{ 
    _foo = value; 
} 

, kendi _foo erişmek istediğiniz her zaman Bu iki arabirimden biri olarak üye olmak için, sırasıyla (IFirstInterface)_foo ya da (ISecondInterface)_foo ya da oyuncular aracılığıyla erişmeniz gerekir.

Derleme zamanı güvenliği için yayınlara başvurmaktan kaçınmak istediğinizi söylediniz; ama bence, _foo'un SetFoo'u kullanarak başlatıldığından emin olmanın bir yolunu bulursanız, istediğiniz herşeyi huzur içinde atabilirsiniz.


Sadece altında gerçekleşmiştir Özellikle sen yapmak istemiyordu söz belirtilen şey anlatır.Yani, diyelim, yukarıdakilerle git.

bu _foo nesne sınıfı üyesi (ben değişken adında _ bu varsayımı kurdum), bu şekilde sınıfınızı tanımlayabiliriz olduğu gibi görünüyor çünkü başka bir fikir, şöyle olacaktır:

class YourClassThatHasAFoo<T> where T : IFirstInterface, ISecondInterface { 
    private T _foo; 

    public void SetFoo(T value) { 
     _foo = value; 
    } 
} 
bu aslında mantıklı olsun

özel senaryo üzerinde, belli ki, bağlıdır. Kesinlikle böyle kısıtlamalarla sınıflar bazen sorunlara neden olarak yolda beklenen olmayabilir, bunun üzerine düşünmeye o uygular (yani SetFoo şimdi tip T bir parametre almalıdır gibi değil, sadece herhangi bir sınıf olacak iki arayüzün).

+0

Siz, efendim, altın bir kurabiye al. Bu kod çok yararlı! –

+0

Not: (IFirstInterface) _foo' kırılgandır. "IFirstInterface" öğesini "T" sınırlamalarınızdan kaldırırsanız, çalışma zamanı yayıncısı olur. Ancak, ör., IFirstInterface _fooFirst = _foo' veya [bir compiletime/static cast aldığınızdan emin olmak için diğer hileleri kullanın] (http://stackoverflow.com/q/3894378/429091). – binki

2

.NET'de bir değişken bir türe sahiptir ve türleri birden fazla arabirim uygulayabilir. Böyle bir şey:

public interface Interface1 { } 
public interface Interface2 { } 
public class SupportsMuliple : Interface1, Interface2 { } 

Ama eğer bir değişken bu arabirimleri kullanan bir türü kalmadan birden çok arabirimi uygulamak istiyorum gibi sorudan görünüyor. Bu gerçekten mümkün değil, ancak ara yüzeyleri uygulayan ve sihir yapan gerçek bir türün olduğunu gizleyen bir tür yaratabilirsiniz. Alay kitaplığı moq bunu Castle DynamicProxy kullanarak yapar. Eğer bu iki arabirimleri uygulayan tek parametrelerini almak için yöntem SetFoo sınırlamak istiyorsanız

+0

Yanıt için teşekkürler. Arabirimleri uygulayan türler zaten var, bunları uygulamada agnostik bir şekilde depolamanın ve kullanmanın bir yoluna ihtiyacım var. –

5

Hayır, bildirimli belirli örneği birden fazla arabirimi uygulayan sağlamak için hiçbir yolu yoktur. Bu gerçekten sadece bir fonksiyonu yerine bir özellik için çalışacak olsa

Seçeneklerden biri, eşdeğer ilaç kullanımıyla mümkün olabilir. tip çıkarımı kullanarak

public void Foo<T>(T arg) 
    where T : IFirstInterface 
    where T : ISecondInterface 
{ 
    ... 
} 

, böyle adlandırmak mümkün olmalıdır:

ConcreteType bar = new ConcreteType(); // this implements both 

Foo(bar); 
1

Bunlardan keyfi kombinasyonları gerekli ve tip-güvenli bir şekilde kullanılabilir, böylece arayüzleri tanımlamak mümkündür . Anahtar bir arabirim iself tanımlamaktır olan bir üye, Kendi, nesne bir T kendisi döner ve daha sonra her bir arayüz IFoo için, (formunda IFoo karşılık gelen bir genel beyan edildiği bir özelliktir, (Çıkış T) Dışarıdan T), hem IFoo hem de ISelf (T) 'den miras alır. (Wowzo ki) iself, IFoo (Wowzo ki), (Wowzo ki) Ibar ve IBoz (Wowzo ki) uygulayan bir sınıfı Wowzo, (İbar'ın) IFoo, (IFoo ki) Ibar, IFoo (IBoz Of (ki implemenet olacak IBar)), IFoo ((IBar) (IBar (IBar) 'dan))), vb. Eğer Thing bir IFoo'yduysa (IBar'dan (IBoz)), doğrudan bir IFoo olarak kullanabilir veya Thing.Self'ı bir IBar olarak kullanabilir veya Thing.Self.Self'ı bir IBoz olarak kullanabilir. C# ile bu şekilde üç arayüzleri birlikte oluşturmak için nasıl

Örnek:

public interface ISelf<out T> 
{ 
    T Self { get; } 
} 
interface IA { } 
interface IA<T> : IA, ISelf<T> { } 
interface IB { } 
interface IB<T> : IB, ISelf<T> { } 
interface IC { } 
interface IC<T> : IC, ISelf<T> { } 
class ConcreteThing 
    : IA<ConcreteThing> 
    , IB<ConcreteThing> 
    , IC<ConcreteThing> 
{ 
    public ConcreteThing Self => this; 
} 
public class ReferencingObject 
{ 
    IA<IB<IC>> Thing { get; } 

    void Method() 
    { 
     IA a = Thing; 
     IB b = Thing.Self; 
     IC c = Thing.Self.Self; 
    } 
} 
İlgili konular