Jaka jest różnica między implementacją interfejsu jawnie lub niejawnie?

64

W Visual Studio mogę kliknąć interfejs prawym przyciskiem myszy i wybrać opcję Implementuj interfejs lub Implementuj interfejs jawnie.

Zrzut ekranu programu Visual Studio

public class Test : ITest
{
    public string Id // Generated by Implement Interface
    {
        get { throw new NotImplementedException(); }
    }

    string ITest.Id // Generated by Implement Interface Explicitly
    {
        get { throw new NotImplementedException(); }
    }
}

Jedyną różnicą, jaką widzę między nimi, jest to, że nazwa interfejsu jest dodawana do właściwości i metod interfejsu, gdy są tworzone, jeśli zdecydujesz się na implementację interfejsu w sposób jawny.

Uważam, że sprawia, że ​​kod jest nieco bardziej czytelny, ponieważ widzę, skąd pochodzi ta metoda / właściwość, ale czy ma to jakikolwiek wpływ na sposób użycia lub kompilacji klasy? Czy to naprawdę ma znaczenie, jeśli implementuję moje interfejsy w sposób dorozumiany lub jawny?

Rachel
źródło

Odpowiedzi:

51

Sprawdź najwyższą odpowiedź Andrew Barretta na „implementację interfejsu domyślnego vs. jawnego” na SO .

Gruntownie:

  • Domniemany: masz dostęp do metod i właściwości interfejsu, jakby były częścią klasy.
  • Jawne: dostęp do metod i właściwości można uzyskać tylko, traktując klasę jako zaimplementowany interfejs.

Przykłady kodu:

Domniemany:

Test t = new Test();
t.Id; // OK
((ITest)t).Id; // OK

Wyraźny:

Test t = new Test();
t.Id; // Not OK
((ITest)t).Id; // OK

Jeśli chodzi o „kiedy” musisz jawnie zaimplementować interfejs, to wtedy, gdy twoja klasa ma już metodę z tym samym podpisem co jedna z metod twojego interfejsu lub gdy twoja klasa implementuje kilka interfejsów, które współużytkują metody z tymi samymi podpisami ale niezgodne umowy.

Jalayn
źródło
1
Uznałem również, że jawna implementacja jest przydatna, aby mieć coś w rodzaju „ukrytego” interfejsu z niebezpiecznymi operacjami. Sprawia również, że wywołania tych metod wyróżniają się bardziej, co jest dobre dla niebezpiecznych rzeczy.
Tamás Szelei
Warto również wspomnieć, że korzystanie z jawnych interfejsów wiąże się z obniżeniem wydajności, ponieważ musi on blokować / rozpakowywać obiekt za każdym razem, gdy odwołujesz się do właściwości / metody. Z tego powodu lepiej jest używać niejawnych interfejsów, jeśli to możliwe
Rachel
3
@Rachel: O ile mi wiadomo, że koszt wydajności dotyczy tylko typów wartości.
Groky
8

Istnieje również różnica w sposobie wywoływania metody.

Korzystając z jawnej implementacji interfejsu, należy użyć typu interfejsu, aby wywołać tę konkretną implementację.

Tak więc, przy wywoływaniu kodu musisz użyć zmiennej typu ITest, aby uzyskać dostęp ITest.Id.

Artykuł Jawna implementacja interfejsu (C # Programming Guide) na MSDN ma dobry przykład.

Oded
źródło
4

Pozwala zaimplementować dwa interfejsy, które definiują tę samą metodę. Jeśli jednak jawnie zaimplementujesz interfejs, dostęp do metod będzie możliwy tylko wtedy, gdy zmienna zostanie wpisana do tego jawnego interfejsu.

Zobacz: Samouczek implementacji interfejsu jawnego

unholysampler
źródło
4

EDYCJA: To nie powinno mieć znaczenia Nie powinieneś tego robić, chyba że twoja klasa zaimplementuje dwa interfejsy o takich samych właściwościach, ponieważ będziesz musiał rzutować na odpowiedni interfejs, zanim będziesz mógł uzyskać dostęp do członka:

public interface ITest
{
    string Id { get; }
}

public interface IAlsoTest
{
    string Id { get; }
}

public interface ITestToo
{
    int Id { get; }
}

public class Test : ITest, IAlsoTest
{
    // Valid implicit implementation of BOTH interfaces
    public string Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestSeparately : ITest, ITestToo
{
    // This way we can do different things depending
    // on which interface the callee called from.
    string ITest.Id
    {
        get { throw new NotImplementedException(); }
    }

    int ITestToo.Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestOuch
{
    public void DoStuff()
    {
        var ts = new TestSeparately();

        // Works
        Console.WriteLine(((ITest)ts).Id);

        // Works
        Console.WriteLine(((ITestToo)ts).Id);

        // Not valid! Which one did we want to call?
        Console.WriteLine(ts.Id);
    }
}

Przykładowe użycie zachodzi, gdy jawnie implementujesz element interfejsu, nawet jeśli używasz tylko jednego interfejsu (o czym zawsze zapominam: S), więc starałbym się unikać implementacji jawnej, gdy tylko jest to możliwe, ponieważ ukryje członków klasy, jeśli „ nie jest przesyłany do odpowiedniego interfejsu (co jest dość mylące).

Ed James
źródło
3

Na podstawie odpowiedzi Jalayana:

  • Domniemany: masz dostęp do metod i właściwości interfejsu, jakby były częścią klasy.
  • Jawne: dostęp do metod i właściwości można uzyskać tylko, traktując klasę jako zaimplementowany interfejs.

wprowadź opis zdjęcia tutaj

Alexander Zaldostanov
źródło