2
var p1 = new Progress<int>(a => progressbar1.Value = a};
p1.Report(1); // нельзя, ошибка компиляции
IProgress<int> p2 = new  Progress<int>{b => progressbar2.Value = b};
p2.Report(2); // можно
  1. Почему нельзя вызвать метод из переменной типа класса, а из переменной типа интерфейса можно?
  2. Для чего так сделано?
4per
  • 2,696
  • 3
    явная реализация интерфейсов, сделана чтобы разделить возможное дублирование наименований методов в разных интерфейсах. – teran Jun 09 '17 at 11:20
  • здрасьте https://ru.stackoverflow.com/questions/1315985/objecta-%d0%b8-objectb-%d0%bd%d0%b5%d0%ba%d0%b8%d0%bc-api – Luke Skywalker Aug 10 '21 at 02:10
  • здрасьте https://ru.stackoverflow.com/questions/1315985/objecta-%d0%b8-objectb-%d0%bd%d0%b5%d0%ba%d0%b8%d0%bc-api – Luke Skywalker Aug 10 '21 at 02:12

1 Answers1

2

Дело в том, что для реализации интерфейса вовсе не обязательно определять все методы этого интерфейса как открытые методы класса. Можно просто указать метод, который будет реализовывать интерфейсный метод, не давая ему вовсе имени:

class Progress<T> : IProgress<T>
{
    void IProgress<T>.Report(T value) { ... }
    // ...
}

При этом метод можно вызвать только через восходящее приведение типа (upcast).

Такая техника называется явной реализацией интерфейса. Обращаясь к документации или подглядывая в исходники можно убедиться, что так оно и есть в случае класса Progress<T>.


(Дополнительная информация по теме.)

Обычно явная реализация интерфейса используется для случая, когда нужно реализовать несколько конфликтующих интерфейсов одновременно. Типичный пример: если мы реализуем IEnumerable<T>, то мы при этом должны реализовать и необобщённый IEnumerable, и нам нужно два метода GetEnumerator: один, возвращающий IEnumerator<T>, и один, возвращающий IEnumerator. Без явной реализации интерфейса это было бы невозможно без трюков (например, вспомогательного промежуточного класса). С явной реализацией обычно пишут так:

class C<T> : IEnumerable<T>
{
    public IEnumerator<T> GetEnumerator() { /* реализация */ }
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

Для чего же так сделано в классе Progress<T>? Можно только гадать, гугл и исходники ответа на вопрос не дали. Нескольких интерфейсов Progress<T> не реализует, так что использование явной реализации не является строго необходимым.

Предположу, что это сделано, чтобы стимулировать передачу в фоновые методы объекта не конкретного типа Progress<T>, а интерфейсного типа IProgress<T> (что позволит легко подменять реализацию на другую).

VladD
  • 206,799
  • Почему нельзя было сделать явную реализацию классов? – Alex78191 Jun 11 '17 at 00:45
  • @Alex78191: А что такое явная реализация классов? – VladD Jun 11 '17 at 00:56
  • Множественное наследование – Alex78191 Jun 11 '17 at 00:58
  • @Alex78191: Не вполне понимаю ваш комментарий. Множественное наследование в C# есть только у интерфейсов. И в случае Progress<T> я не вижу, как и куда его применить. У нас есть один класс и один интерфейс, как тут устроить множественное наследование? – VladD Jun 11 '17 at 01:00
  • Вот именно его нет и спрашиваю почему не сделали. – Alex78191 Jun 11 '17 at 01:12
  • @Alex78191: А для чего? Какую проблему оно в принципе могло бы решить? И как его тут можно было бы устроить? Покажите, если вам не сложно, код, который вы имеете в виду, потому что на словах мне не понятна ваша идея. – VladD Jun 11 '17 at 01:43