Подтвердить что ты не робот

Разница между реализацией интерфейса и применением атрибута в С#

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

Я читал "ООП Демистифицированный: руководство по самообучению Джим Кеог и Марио Джаннини", глава 11, который охватывает интерфейсы. Примеры в этой книге - С++.

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

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

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

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

Был бы благодарен за разъяснение.

Спасибо.

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

[Serializable]
class Foo : ISerializable
{
}

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

Ответ 4

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

Существуют и другие аспекты интерфейсов:

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

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

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

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

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

Ответ 5

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

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

Ответ 6

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

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