Как вы думаете, "автоматическая реализация интерфейса" будет полезна in.NET / C# [закрыто]


Рассмотрим это:

public class interface Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

И это:

public class StubPerson : IPerson
{
    int ID { get { return 0; protected set { } }
    string FirstName { get { return "Test" } set { } }
    string LastName { get { return "User" } set { } }
    string FullName { get { return FirstName + " " + LastName; } }
}

Использование:

IPerson iperson = new Person();

Или:

IPerson ipersonStub = new StubPerson();

Или:

IPerson ipersonMock = mocks.CreateMock<IPerson>();

Таким образом, фактически мы объявляем интерфейсIPerson и класс Person одновременно:

public class interface Person : IPerson

Как вы думаете, было бы полезно иметь такую поддержку в .NET / C#?

Редактировать:

Из-за массовой путаницы я думаю, что мне нужно уточнить предлагаемую цель:

Без этой функции вам придется написать:

interface IPerson
{
  int ID { get; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get; }
}

А также это:

public class Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

Я не предлагаю никаких семантических изменений вообще.

9 5

9 ответов:

Я рассматривал то же самое некоторое время назад, особенно для использования в случае, когда у вас есть только одна производственная реализация интерфейса, но вы хотите смоделировать его для тестирования. На данный момент это немного похоже на то .с/.h файлы былых времен.

В конце концов, я подозреваю, что преимущества этого перевешиваются дополнительной сложностью как в языке, так и в последующем чтении кода. Хотя мне все равно было бы интересно увидеть его более тщательно исследованным. Даже тогда, есть другие вещи намного выше в моем списке приоритетов-лучшая поддержка неизменности, находящейся в верхней части :)

Позвольте мне посмотреть, понимаю ли я, о чем вы спрашиваете:

Почему мы не можем объявить интерфейс:

interface IPerson
{
    string Name {get;set;}
    int ID {get;set;}
}

И классы, реализующие этот интерфейс, унаследуют его свойства без необходимости их повторного объявления:

class Person : IPerson { } 
//person now has properties Name and ID
Причина, по которой вы не можете этого сделать, заключается в том, что, хотя текст вашего кода интерфейса и кода класса очень похожи, они означают очень разные вещи. Интерфейс просто говорит: "у реализатора будет строковое имя с геттером и сеттером". Это класс, который говорит " return private field when getter for name вызывается."Даже если вы используете ярлык auto-property, чтобы позволить компилятору реализовать эту логику, это все равно логика , которая принадлежит классу. Просто потому, что:
string Name {get;set;}

выглядит одинаково в интерфейсе и в классе, это не означает даже отдаленно одно и то же.

Для компилятора было бы очень опасно реализовывать произвольную логику для выполнения ваших контрактов вместо вас. жаловаться во время компиляции, что вы их не реализовали. Это может привести к появлению ошибок, которые очень трудно отследить. Если компиляторы возвращаются к поведению по умолчанию, когда поведение не определено, это очень, очень плохая идея.

Я полагаю, что Eiffel делает нечто подобное в .NET, чтобы поддержать множественное наследование. Объявление класса автоматически создает соответствующий интерфейс. Когда ссылаются на тип класса, компилятор в основном выдает ссылку на тип интерфейса. Главное исключение, конечно, в конструкторах выражений.

Ну, я думаю, что другие ответы помогут вам понять использование интерфейса для абстрактной логики в различных конкретных классах, я также думаю, что вы можете достичь чего-то похожего на то, что вы хотите, используя инструменты рефакторинга, встроенные в VS.

Определите свой класс...

public class Person
{
  public int ID { get; protected set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string FullName { get { return FirstName + " " + LastName; } }
}

Затем щелкните правой кнопкой мыши, выберите Рефактор - > извлечь интерфейс.

Это создаст отдельный файл, содержащий интерфейс для определения класса, вы можете затем сформировать интерфейс и реализация классов соответственно.

Извлеченный Интерфейс:

interface IPerson
{
    string FirstName { get; set; }
    string FullName { get; }
    int ID { get; }
    string LastName { get; set; }
}

Я думаю, что упускаю суть - чего вы добиваетесь, смешивая класс и интерфейс вместе? Какую проблему вы решаете с помощью этого подхода?

Это:

IPerson iperson = new Person();

Уже легально в C#.

Edit: для уточнения-приведенный выше код является юридическим, учитывая следующее:

interface IPerson { }

class Person : IPerson { }

Я хотел бы, по крайней мере, чтобы Visual Studio реализовал мои свойства из интерфейса как свойства auto, если я попрошу его сделать это.

К сожалению, эта опция не работает, и мне приходится иметь дело с не реализованными заглушками исключений

Нет, потому что вы были бы вынуждены предоставить доступ ко всем открытым членам интерфейса. ПопробуйтеReSharper , и никогда больше не беспокойтесь об этом.

Resharper может обеспечить эту функциональность, например,

  1. сначала вы можете написать свой личный класс.
  2. вы можете извлечь свой интерфейс с помощьюподтягивания членов к интерфейсу IPerson.

Следовательно, вы можете иметь Visual Studio автоматически генерировать заглушки реализации для вас.

Обновить

В любом случае, давайте сначала поговорим об интерфейсах, ссылаясь на код, который вы предоставили в своем вопросе:
public class interface Person : IPerson
{
    int ID { get; protected set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get { return FirstName + " " + LastName; } }
}

Вы должны понимать, что Интерфейс - это не абстрактный класс. Интерфейс-это простоконтракт , своего рода чертеж, который означает, что он будет говорить объекту, чего ожидать от другого объекта, не заботясь о том, как он реализуется.

С другой стороны, абстрактный класс может содержать фрагменты функциональности, которые могут быть унаследованы и переопределены.

В приведенном выше случае ваш" интерфейс " недействителен, потому что:

  • нельзя объявлять ограничения области видимости для интерфейсов (публичный, частный, защищенный, внутренний), поскольку это деталь реализации
  • вы не можете объявить реализацию по умолчанию (например, ваше СВОЙСТВО FullName), потому что это опять же деталь реализации

Мне кажется, что вы действительно хотите абстрактный класс, например,

public abstract class BasePerson
{
    public abstract int ID { get; protected set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual string FullName { get { return FirstName + " " + LastName; } } 
}
Я просто предполагаю, но, может быть, это то, что вам действительно нужно.

Обновление 2

Хорошо, я думаю, что я добрался до того, что ты хочешь, чтобы произошло, так что ты хочешь быть в состоянии написать это:
public interface IPerson
{
    int ID { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get; }
}

И тогда для вашей реализации нужно только написать следующее:

public class Person : IPerson
{
    public int ID { get; protected set; }
    public string FullName { get { return FirstName + " " + LastName; } } 
}

Без необходимости указывать свойства FirstName и LastName.

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

Второй является тот факт, что в то время как в наших глазах string FirstName { get; set; } в интерфейсе и public string FirstName { get; set; } в классе то же самое, они на самом деле не являются:

  • в интерфейсе определение свойства будет указывать, что сигнатуры метода для методов getter и / или setter будут доступны для всех классов, реализующих этот интерфейс.
  • в классе определение свойства указывает среде CLR создать анонимный объект, который будет содержать значение указанного свойства.

Тонкая разница для программиста, миры друг от друга для компилятор.

Наконец, когда вы указываете, что вы реализуете интерфейс, Visual Studio выполняет synctactic magic, которая автоматически создает эти заглушки свойств для вас.

Я думаю, что лучшей абстракцией для этого является черта, или, как я описал здесь , роль. Это как интерфейс с кодом. Ваш пример может быть закодирован следующим образом:

public role RPerson { 
  int ID { get; protected set; } 
  string FirstName { get; set; } 
  string LastName { get; set; } 
  string FullName { get { return FirstName + " " + LastName; } } 
} 

public class Person : RPerson { }

public class StubPerson : RPerson { 
    int ID { get { return 0; protected set { } } 
    string FirstName { get { return "Test" } set { } } 
    string LastName { get { return "User" } set { } } 
    string FullName { get { return FirstName + " " + LastName; } } 
} 

// ...

RPerson rperson = new Person(); 

RPerson rpersonStub = new StubPerson();