2014-05-18 11 views
11

staram się osiągnąć coś takiego:Generics IAbstract <T> dziedziczy z IAbstract

interface IAbstract 
{ 
    string A { get; } 
    object B { get; } 
} 

interface IAbstract<T> : IAbstract 
{ 
    T B { get; } 
} 

class RealThing<T> : IAbstract<T> 
{ 
    public string A { get; private set; } 
    public T B { get; private set; } 
} 

Więc mogę zrobić coś takiego:

RealThing<string> rt = new RealThing<string>(); 
IAbstract ia = rt; 
IAbstract<string> ias = rt; 
object o = ia.B; 
string s = ias.B; 

Czy to możliwe?

+1

Dobrym przykładem tego dokładnego wzorca w środowisku .NET jest ['IEnumerable'] (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx) i [' IEnumerable '] (http://msdn.microsoft.com/en-us/library/9eekhta0 (v = vs.110) .aspx) gdzie' IEnumerable' ma 'IEnumerator GetEnumerator()' i 'IEnumerable ' robi dokładnie to samo, co robisz ze swoimi właściwościami za pomocą 'IEnumerator GetEnumerator()'. –

Odpowiedz

10

Prawie prawie. Trzy rzeczy:

  • należy użyć new w IAbstract<T> aby wskazać, że wiesz, że ukrywanie istniejącego użytkownika:

    new T B { get; } 
    

    Ale nawet bez tego, nadal będziesz tylko dostać ostrzeżenie.

  • Trzeba wdrożyć IAbstract.B ciągu RealThing, która powinna prawie na pewno nie przy użyciu wyraźnej wdrożenie interfejsu, delegowaniu do silnie wpisany użytkownik:

    object IAbstract.B { get { return B; } } 
    
  • w kodzie testowym, należy określić argument typu dla RealThing:

    RealThing<string> rt = new RealThing<string>(); 
    

jest grzywny, a nawet dość powszechny wzorzec dla czasów, w których chcesz uzyskać nietypową formę interfejsu.

10

Tak, z małymi zmianami

interface IAbstract 
{ 
    string A { get; } 
    object B { get; } 
} 

interface IAbstract<T> : IAbstract 
{ 
    new T B { get; } 
} 

sealed class RealThing<T> : IAbstract<T> 
{ 
    public string A { get; private set; } 
    public T B { get; private set; } 

    object IAbstract.B 
    { 
     get { return B; } 
    } 
} 

więc można napisać

var rt = new RealThing<string>(); 
IAbstract ia = rt; 
IAbstract<string> ias = rt; 
object o = ia.B; 
string s = ias.B; 
+1

Czy właściwość 'B' na' IAbstract 'nie powinna być oznaczona słowem kluczowym' new', aby cienie były jawne? –

+0

Oczywiście, moja wina, naprawiony, dzięki! – GSerjo

1

Właściwie interfejsy System.Collections.IEnumerator i System.Collections.IEnumerator<T> zrobić. Podczas wdrożenia IEnumerable<T>, trzeba będzie wdrożyć jedną z właściwości Current wyraźnie, zazwyczaj można wybrać nierodzajową jeden dla że:

object IEnumerable.Current 
{ 
    // this calls the implicitly implemented generic property 
    get { return this.Current; } 
} 

public T Current 
{ 
    get { return this.current; } // or however you want to do it 
} 
1

W tym przypadku nie trzeba nawet dwa interfejsy. Wystarczy zaznaczyć interfejs jako kowariantna (obsługiwany od C# 4):

interface IAbstract<out T> 
{ 
    string A { get; } 
    T B { get; } 
} 

i używać IAbstract<object> gdziekolwiek użył non interfejs rodzajowe wcześniej.

+0

Dzięki.Moim przypadkiem użycia jest to, że muszę go używać jako typ parametryczny. Myślę, że 'List ' jest ładniejszym sposobem na zrobienie tego. – Cheetah