Разница между реализацией интерфейса и применением атрибута в C # - PullRequest
20 голосов
/ 19 апреля 2010

Это может быть глупый вопрос, но я все равно задам,

Я читал главу 11 «Описано ООП: самоучитель Джима Кеога и Марио Джаннини», в которой рассматриваются интерфейсы. Примеры в этой книге: C ++.

Я заметил, что C ++ использует ISerializable для создания сериализуемого класса, который вы реализуете, где, как в C #, вы просто приписываете класс с атрибутом [Serializable].

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

Я предполагаю, что с атрибутом [Serializable] .Net Framework использует отражение, чтобы сделать сериализованный объект из фактического объекта.

Тем не менее, возможно ли в этом случае иметь атрибут [Disposable] или, используя мою теорию выше рамок, не будет знать, как на самом деле избавиться от объекта, следовательно, вам придется делать это самостоятельно?

Буду признателен за разъяснения.

Спасибо.

Ответы [ 6 ]

10 голосов
/ 19 апреля 2010

Давным-давно в галактике далеко-далеко ... Не было Атрибутов или поддержки компиляторов для метаданных классов, поэтому разработчики пытались реализовать свои собственные. Один из методов, которые разработали наши предки, состоял в том, чтобы объявить Маркерные интерфейсы .

Итак, чтобы ответить на ваш вопрос: пользовательские атрибуты - это «эволюция» маркерных интерфейсов. Вы можете использовать оба. Но учтите, что если вы хотите, чтобы ваш объект реализовывал определенные методы, вы используете простой и понятный интерфейс. Вот как работает IDisposable, это заставляет вас реализовать метод с именем Dispose(). [Serializable] (и, вероятно, ISerializable в вашем примере на C ++) не заставляет вас что-либо реализовывать, поскольку среда выполнения просто читает это объявление и выполняет свою задачу (т.е. сериализует объект).

Обратите внимание, что C # также имеет интерфейс ISerializable ... Он предназначен для того, чтобы позволить вам написать свой собственный код сериализации, который затем будет вызываться во время выполнения. Обратите внимание, что он НЕ является интерфейсом маркера и не заменяет атрибут [Serializable], так как вам все равно нужно пометить свой класс атрибутом для сериализации.

6 голосов
/ 19 апреля 2010

Атрибуты обычно предоставляют дополнительные метаданные о типе или элементе; существуют значительные ограничения в отношении того, что разрешено (значения const и т. д.), и Эрик Липперт высказал некоторые соображения по поводу различий между интерфейсами и свойствами , которые могут быть светящимися.

Есть несколько других аспектов интерфейсов:

  • они могут иметь несколько членов
  • За интерфейсом лежит некоторая реализация (это очень важно)
  • вы можете использовать интерфейс для абстракции (не столько атрибут)

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

Тот факт, что Foo сериализуем, не означает, что Bar (:Foo) обязательно должен быть сериализуемым; так что приятно иметь возможность определять это на каждом уровне - хотя на самом деле я не думаю, что BinaryFormatter должна быть ключевой частью кода сериализации mots (хотя я укушу язык).

На самом деле, если вы проверите IL, вы увидите, что [Serializable] не на самом деле записывается как атрибут - вместо этого это флаг CLI (некоторая магия компилятора). Но это не меняет факт.

Если все, что вам нужно сделать, это выразить метаданные (факты о типе / члене), атрибуты идеальны. Если вам нужно выразить поведение / API, то интерфейс.

5 голосов
/ 19 апреля 2010

Большинство атрибутов будут проверяться только во время выполнения. Некоторые проверяются во время компиляции (см. Атрибут условный , как упомянуто ниже). По большей части, с атрибутом вы должны использовать отражение, чтобы увидеть, обладает ли объект им, и принять решение о том, что делать дальше.

Интерфейс - это реализация компилятора. С помощью интерфейса вы можете требовать, чтобы параметры реализовывали его для методов и т. Д.

Атрибуты: http://msdn.microsoft.com/en-us/library/z0w1kczw.aspx

Интерфейсы: http://msdn.microsoft.com/en-us/library/ms173156.aspx

4 голосов
/ 19 апреля 2010

Я думаю, вы упустили тот факт, что .NET (C #) также имеет интерфейс ISerializable:

[Serializable]
class Foo : ISerializable
{
}

Атрибут «пользовательские метаданные», интерфейс - языковая функция.

2 голосов
/ 19 апреля 2010

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

Вы должны явно предоставить BinaryFormatter право сделать это, по существу признавая, что объект вашего класса может быть десериализован без проблем. Вы делаете это, применяя атрибут [Serializable]. BinaryFormatter просто проверяет, присутствует ли он. Вот и все.

1 голос
/ 19 апреля 2010

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

Существует небольшое снижение производительности при проверке класса для атрибута во время выполнения по сравнению с проверкой типа во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...