2017-04-20 15 views
21

I naprawdę trzeba mieć coś takiego:Getter i seter pochodzących z różnych interfejsów

interface IReadableVar 
{ 
    object Value { get; } 
} 

interface IWritableVar 
{ 
    object Value { set; } 
} 

interface IReadableWritableVar : IReadableVar, IWritableVar 
{ 
} 

Jednak gdy próbuję użyć IReadableWritableVar.Value otrzymuję błędy kompilacji, chyba że wyraźnie oddane do interfejsu bazowego, jak tutaj:

static void Main() 
{ 
    IReadableWritableVar var = null; 
    var t = var.Value; // <-- CS0229: Ambiguity between 'IReadableVar.Value' and 'IWritableVar.Value' 
    var.Value = null; // <-- CS0229: Ambiguity between 'IReadableVar.Value' and 'IWritableVar.Value' 

    var v = ((IReadableVar)var).Value; // compiles fine 
    ((IWritableVar)var).Value = null; // compiles fine 
} 

Dlaczego pojawiają się te błędy, mimo że wszystko powinno być jasne dla kompilatora? Czy jest jakiś sposób na rozwiązanie tego problemu poza rzutowaniem (setki miejsc w aplikacji)?

Aktualizacja: zasugerowano, że jest to duplikat Implementing 2 Interfaces with 'Same Name' Properties, ale jest to nieco inne, ponieważ w drugim przypadku nie ma dziedziczenia w interfejsach. W każdym razie problem został rozwiązany teraz - patrz zaakceptowana odpowiedź.

+0

myślę kompilator nie jest zaprojektowany, że sposób na odróżnienie identycznych właściwości w różnych interfejsach na podstawie programu pobierającego lub ustawiającego –

+0

Możliwy duplikat opcji [Implementing 2 Interfaces with 'Same Name'] (http://stackoverflow.com/questions/532148/implementing-2-interfaces-with- same-nazwy-własności) – PJvG

+2

Należy zauważyć, że 'IWritableVar' jest podejrzany, ponieważ właściwości tylko do zapisu są podejrzane. Każdy dzwoniący, który może napisać właściwość, powinien prawdopodobnie być w stanie ją odczytać, a tam, gdzie to nie ma sensu, prawdopodobnie potrzebujesz metody, a nie właściwości. –

Odpowiedz

16

Możliwe obejście można zmodyfikować interfejs IReadableWritableVar tak:

interface IReadableWritableVar : IReadableVar, IWritableVar 
{ 
    new object Value { get; set; } 
} 

jednak zachować w moim, że ważna realizacja powinna być:

class ReadableWritableVar : IReadableWritableVar 
{ 
    public object Value 
    { 
     get { throw new NotImplementedException(); } 
     set { throw new NotImplementedException(); } 
    } 

    object IWritableVar.Value 
    { 
     set { throw new NotImplementedException(); } 
    } 

    object IReadableVar.Value 
    { 
     get { throw new NotImplementedException(); } 
    } 
} 

Bardziej konkretny przykład:

class ReadableWritableVar : IReadableWritableVar 
{ 
    public object Value 
    { 
     get { return ((IReadableVar)this).Value; } 
     set { ((IWritableVar)this).Value = value; } 
    } 

    object _val; 

    object IWritableVar.Value { set { _val = value; } } 

    object IReadableVar.Value => _val; 
} 

Albo jeszcze lepiej:

class ReadableWritableVar : IReadableWritableVar 
{ 
    public object Value { get; set; } 

    object IWritableVar.Value { set { Value = value; } } 

    object IReadableVar.Value => Value; 
} 
+1

Zastanawiam się, w jaki sposób będzie on używany? –

+2

Wystarczy notatkę: nie potrzebujesz jawnych implementacji. 'class ReadableWritableVar: IReadableWritableVar { { obiekt publiczny Wartość {get; zestaw; } } 'kompiluje się dobrze. – vyrp

+1

Po prostu dodanie właściwości 'new Value' do 'IReadableWritableVar' rozwiązało problem dla mnie. Klasa implementująca to wykonywała nie-jawną implementację. To obejście, ale działa świetnie - wielkie dzięki. – Arek

0

użycie interfejsu klasy abstrakcyjnej rozwiąże problem.

+1

Ale nie nazywaj tego 'IReadableWritableVar' jeśli nie jest to interfejs, nazwij go' ReadableWritableVar' lub 'AbstractReadableWritableVar'. – PJvG

+0

@PJvG, masz rację. dzięki – daniell89

+0

Niestety musi to być interfejs, a klasa implementująca go implementuje więcej z nich. – Arek

3

Cóż, skutecznie Getter i Setter to tylko dwie metody. Kiedy używamy interfejsu IReadableWritableVar, istnieją dwie metody o identycznej nazwie odziedziczone po interfejsach bazowych, a kompilator nie wie, którego z nich należy użyć, stąd dwuznaczność.

Kiedy rzuca się to na jeden z tych interfejsów, drugi członek zniknął i nie ma błędu.

Jeśli wdrożymy te państwa nie będzie żadnego błędu jak kompilator użyje tej realizacji:

class ReadableWritableVar : IReadableWritableVar 
{ 
    public object Value { get; set; } 
} 

var @var = new ReadableWritableVar(); 
var t = @var.Value; 

Również można użyć jawnego interfejsu od implementacji członków odpowiedź @Alessandro D'Andria, jeśli jest to wymagane że korzystasz z interfejsu, a nie z klasy.

+0

To są tylko metody wewnętrznie, ale myślę, że dwie różne metody. Dlatego nie rozumiem, dlaczego kompilator zachowuje się w ten sposób. Gdybym użył dwóch metod (setter i getter) zamiast własności, problem nie istniałby. – Arek

7

Interesujące pytanie. Myślę, że metody rozszerzenia pomogą w tym przypadku.

public static class Extension 
{ 
    public static object GetValue(this IReadableVar v) 
    { 
     return v.Value; 
    } 

    public static void SetValue(this IWritableVar v, object value) 
    { 
     v.Value = value; 
    } 
} 

trzeba zmienić kod, aby go użyć:

IReadableWritableVar variable = null; 
var t = variable.GetValue(); 
variable.SetValue(null); 

Metoda rozszerzenie ma obsadę dla Ciebie.

+0

To interesujące podejście, ale w takim przypadku użyłbym metod 'SetValue' i' GetValue' i całkowicie pozbyłbym się właściwości. Niestety wymagana jest własność, ponieważ musi działać z systemem wiążącym WPF. – Arek

0

Możliwym rozwiązaniem jest użycie wyraźny (styl Java) pobierania i ustawiania metod zamiast nieruchomości:

interface IReadableVar 
{ 
    object GetValue(); 
} 

interface IWritableVar 
{ 
    void SetValue(object value); 
} 

interface IReadableWritableVar : IReadableVar, IWritableVar 
{ 

} 

Wykorzystanie wówczas postać:

static void Main(string[] args) 
{ 
    IReadableWritableVar aVar = null; 

    var t = aVar.GetValue(); 
    aVar.SetValue(null); 
} 
+0

Niestety, musi to być właściwość ze względu na system wiążący WPF, który będzie z tego korzystał. – Arek

+1

Powiedziałeś, że to dotyczy sprzętu, bezpośrednio z powiązań w WPF? Potrzebujesz więcej warstw tutaj. –

+0

@BryanBoettcher Cóż, w rzeczywistości mam więcej warstw. Ale wciąż coś, co może być napisane tylko na poziomie sprzętu, jest jedyną właściwością do zapisu na tych warstwach ... – Arek

Powiązane problemy