Какие проблемы отражение решает?

Свифт

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
    if text == "\n" {
        textView.resignFirstResponder()
    }
    return true
}

and configure

15
задан Bill the Lizard 16 September 2012 в 22:25
поделиться

4 ответа

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

Отражение в .NET имеет 2 аспекта:

Исследование информации о типах

Без своего рода API отражения / интроспекции, становится очень сложно выполнять такие вещи, как сериализация. Вместо того, чтобы предоставлять это во время выполнения (путем проверки свойств / полей / и т.д.), вам часто требуется вместо этого генерация кода, то есть код, который явно знает, как сериализовать каждый из ваших типов. Утомительно и болезненно, если вы хотите сериализовать что-то, у чего нет двойника.

Точно так же негде хранить дополнительные метаданные о свойствах и т. Д., так что в итоге у вас будет много дополнительного кода или внешних файлов конфигурации. Такая простая вещь, как возможность связать понятное имя со свойством (через атрибут), является огромным выигрышем для кода пользовательского интерфейса.

Метапрограммирование

Рефлексия .NET также предоставляет механизм для создания типов (и т.д.) во время выполнения, который очень эффективен для некоторых конкретных сценариев; альтернативы:

  • по существу запуск дерева синтаксического анализа / логики во время выполнения (вместо компиляции логики во время выполнения в исполняемый код) - намного медленнее
  • , но больше генерации кода - ура!
14
ответ дан 1 December 2019 в 03:05
поделиться

Я думаю, чтобы понять необходимость отражения в .NET, нам нужно вернуться к .NET. В конце концов, современные языки, такие как Java и C #, не имеют истории BF (до рефлексии).

C ++, возможно, оказал наибольшее влияние на C # и Java. Но в C ++ изначально не было отражения, и мы кодили без него, и нам удалось обойтись. Иногда у нас был указатель void, и мы использовали приведение, чтобы принудительно преобразовать его в любой желаемый тип. Проблема здесь заключалась в том, что приведение могло потерпеть неудачу с ужасными последствиями:

double CalculateSize(void* rectangle) {
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight());
}

Теперь есть много аргументов, почему вы не должны были закодировать себя в первую очередь. Но проблема мало чем отличается от .NET 1.1 с C #, когда у нас не было дженериков:

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    return ((Rect)shape).Width * ((Rect)shape).Height;
}

Однако, когда пример C # терпит неудачу, это происходит с исключением, а не с потенциальным дампом ядра.

Когда отражение было добавленный в C ++ (известный как идентификация типа во время выполнения или RTTI), он горячо обсуждался. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие Иногда у нас был указатель void, и мы использовали приведение, чтобы принудительно преобразовать его в любой желаемый тип. Проблема здесь заключалась в том, что приведение могло потерпеть неудачу с ужасными последствиями:

double CalculateSize(void* rectangle) {
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight());
}

Теперь есть много аргументов, почему вы не должны были закодировать себя в первую очередь. Но проблема мало чем отличается от .NET 1.1 с C #, когда у нас не было дженериков:

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    return ((Rect)shape).Width * ((Rect)shape).Height;
}

Однако, когда пример C # терпит неудачу, это происходит с исключением, а не с потенциальным дампом ядра.

Когда отражение было добавленный в C ++ (известный как идентификация типа во время выполнения или RTTI), он горячо обсуждался. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие Иногда у нас был указатель void, и мы использовали приведение, чтобы принудительно преобразовать его в любой желаемый тип. Проблема здесь заключалась в том, что приведение могло потерпеть неудачу с ужасными последствиями:

double CalculateSize(void* rectangle) {
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight());
}

Теперь есть много аргументов, почему вы не должны были закодировать себя в первую очередь. Но проблема мало чем отличается от .NET 1.1 с C #, когда у нас не было дженериков:

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    return ((Rect)shape).Width * ((Rect)shape).Height;
}

Однако, когда пример C # терпит неудачу, это происходит с исключением, а не с потенциальным дампом ядра.

Когда отражение было добавленный в C ++ (известный как идентификация типа во время выполнения или RTTI), он горячо обсуждался. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие

double CalculateSize(void* rectangle) {
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight());
}

Есть много аргументов, почему вам вообще не следовало закодировать себя в этой проблеме. Но проблема мало чем отличается от .NET 1.1 с C #, когда у нас не было дженериков:

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    return ((Rect)shape).Width * ((Rect)shape).Height;
}

Однако, когда пример C # терпит неудачу, это происходит с исключением, а не с потенциальным дампом ядра.

Когда отражение было добавленный в C ++ (известный как идентификация типа во время выполнения или RTTI), он горячо обсуждался. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие

double CalculateSize(void* rectangle) {
    return ((Rect*)rectangle)->getWidth() * ((Rect*)rectangle)->getHeight());
}

Есть много аргументов, почему вам вообще не следовало закодировать себя в этой проблеме. Но проблема мало чем отличается от .NET 1.1 с C #, когда у нас не было дженериков:

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    return ((Rect)shape).Width * ((Rect)shape).Height;
}

Однако, когда пример C # терпит неудачу, это происходит с исключением, а не с потенциальным дампом ядра.

Когда отражение было добавленный в C ++ (известный как идентификация типа во время выполнения или RTTI), он горячо обсуждался. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие

Когда в C ++ было добавлено отражение (известное как идентификация типа во время выполнения или RTTI), это вызвало горячие споры. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие

Когда в C ++ было добавлено отражение (известное как идентификация типа во время выполнения или RTTI), это вызвало горячие споры. В книге Страуструпа «Дизайн и эволюция C ++» он перечисляет следующие аргументы против RTTI в том, что некоторые люди:

 Объявили поддержку ненужной
Объявлен новый стиль злом по своей сути («против духа C ++»)
Считал это слишком дорогим
Думал, что это слишком сложно и запутанно
Считал это началом лавины новых функций

Но это позволяло нам запрашивать тип объектов или их характеристики. Например (с использованием C #)

Hashtable shapes = new Hashtable();
....
double CalculateSize(object shape) {
    if(shape is Rect) {
        return ((Rect)shape).Width * ((Rect)shape).Height;
    }
    else if(shape is Circle) {
        return Math.Power(((Circle)shape).Radius, 2.0) * Math.PI;
    }
}

Конечно, при правильном планировании этот пример никогда не должен возникать.

Итак, реальные ситуации, когда мне это нужно, включают:

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

Итак, я бы пошел дальше, чтобы утверждать, что Reflection не позволяет делать то, что невозможно сделать перед. Тем не менее, это упрощает кодирование некоторых типов проблем, делает их более понятными для читателя. короче писать и т.д.

Конечно это только мое мнение, могу ошибаться.

9
ответ дан 1 December 2019 в 03:05
поделиться

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

MyObj Function args //textfile.txt

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

char *str; //read in some type from a text file say the string is "MyObj"
str *obj;  //cast a pointer as type MyObj  
obj = new str;  //create a MyObj

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

1
ответ дан 1 December 2019 в 03:05
поделиться

Это очень помогает, когда вы используете в коде атрибуты C #, такие как [Obsolete] или [Serializable]. Такие фреймворки, как NUnit , используют отражение классов и содержат методы, чтобы понять, какие методы являются тестами, настройкой, разборкой и т. Д.

0
ответ дан 1 December 2019 в 03:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: