5

Рассмотрим это:Как вы думаете, "реализация интерфейса авто" будет полезно в .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#?

Edit:

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

Без этой функции вы должны написать:

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; } } 
} 

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

+0

Вы уже можете это сделать ... –

+0

Как? public class interface Person: IPerson {} не будет компилироваться с C# 3.0 –

+0

Это не имеет смысла. Если человек внедряет IPerson, вы можете сделать IPerson p = new Person(); –

ответ

4

Я считал the same sort of thing a while ago, особенно для использования в случае, когда у вас есть только одна производственная реализация интерфейса, но вы хотите издеваться над ним для тестирования. В настоящий момент это немного напоминает файлы .c/.h.

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

+0

Да! Это та самая мысль, что у меня была. Я начинаю склоняться к философии, когда все классы должны реализовывать интерфейс. Не подумал об этом, хотя, возможно, это кандидат на другой вопрос. –

+0

Точно мои мысли тоже. Единственное, что я пропустил в C# из моих дней C++, - это некоторый индекс заголовка всех классов. Мне нравится способ, которым он способствует инкапсуляции, поскольку вы можете изменить реализацию, но вы чувствуете. Im unsure о добавленной сложности, хотя .. – cwap

1

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

Это:

IPerson iperson = new Person(); 

уже легальным в C#.

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

interface IPerson { } 

class Person : IPerson { } 
+0

Я не уверен, что вы думаете. Я знаю, что я могу объявить класс и интерфейс в одном файле, но мне все равно нужно объявить оба. –

+0

Итак, что вы хотите сделать, объявить их сразу? Разве это не помешало бы вам реализовать этот интерфейс на любом другом типе? И если да, то зачем вообще заниматься интерфейсом? Как реализовать в своем примере интерфейс IPerson второго типа? –

+0

Вы не должны проголосовать за это. Ваш вопрос не имеет смысла, поэтому вам не следует ожидать громкого «ДА!». ответ. –

0

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

11

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

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

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

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

class Person : IPerson { } 
//person now has properties Name and ID 

причина вы не можете сделать это, даже если текст вашего кода интерфейса и код класса очень похожи, они средний очень различные вещи. Интерфейс просто говорит: «У конструктора будет строка Name с getter и setter». Это класс, который говорит «return private field при вызове getter для имени». Даже если вы используете ярлык auto-property, чтобы компилятор реализовал эту логику, все равно логический, который принадлежит к классу. Просто потому, что:

string Name {get;set;} 

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

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

+0

@ Андрей, да, я, возможно, решил загадку! ура для меня :) –

+0

@Rex M У классов не выставляются контракты? –

+0

@jonathan да и нет, но я не вижу, как это имеет отношение к рассматриваемому вопросу. Это еще одна дискуссия сама по себе. –

0

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

  1. Вы можете написать свой класс Person первым.
  2. Вы можете извлечь свой интерфейс по адресу pulling members up в интерфейс IPerson.

Следовательно, у вас могут быть созданные для Visual Studio ауты создания экземпляра Visual Studio.

UPDATE

Во всяком случае, давайте изложим на интерфейсах первыхов, ссылаясь на код, который вы предоставили в вопросе:

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; } } 
} 

Я просто угадать, но может быть, это то, что вам действительно нужно.

UPDATE 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 выполняет синтаксическую магию, которая автоматически делает эти заглушки для вас.

+0

Это IDE-сахара (хотя очень полезно!), Я думаю, что искатель хочет знать, почему классы не «наследуют» от своих интерфейсов на уровне языка. –

+0

Rex, touchhe, я расширил свой ответ, чтобы включить объяснения re интерфейсов. –

+0

@Jon Limjap. Если я использую абстрактный класс, то как я могу создать другой класс, который наследует BasePerson, а также из другого класса. Например. public class SpecialPerson: System.Web.UI.Control, BasePerson не будет компилироваться. Примечание. Я использовал класс Control только потому, что это конкретный класс. –

2

Ну, я думаю, что другие ответы помогут вам понять использование интерфейса для абстрактной логики в разных конкретных классах, я также думаю, что вы можете сделать что-то похожее на то, что хотите, используя инструменты рефакторинга, встроенные в 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; } 
} 
+2

Да, за исключением того, что теперь у вас есть дублирование, потому что, когда вы не измените ни класс, ни интерфейс, вы должны изменить другой. –

+0

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

3

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

+0

Теперь это действительно взломать. –

+0

Аналогично, за исключением того, что в моем случае его семантически эквивалентно классу и интерфейсу. –

+0

Это хак, или это отображение уже существующей полной объектной модели на более элементарные концепции, предоставляемые новой платформой? :) Отсутствие поддержки истинного ИМ в платформе - проблема. Без этого интерфейсы невозможно развить. Они должны быть такими же, как все абстрактные классы. –

1

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

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

+0

Sekhat, я уверен, что вы нашли это к настоящему времени, но конфигурацию можно обновить; см. http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/e476d4cf-2d44-4c6a-b7b0-752518467f00/ (размещение для будущих людей, которые находят это сообщение). –

+0

А, нет, на самом деле я этого не делал. Большое спасибо :) – Sekhat

0

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

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();