Действительно ли возможно назвать операторы типа значения через отражение?

О расположении памяти

Как примечание стороны, проблема со Страшным Ромбом состоит в том, что базовый класс присутствует многократно. Таким образом с регулярным наследованием, Вы полагаете, что имеете:

  A
 / \
B   C
 \ /
  D

, Но в расположении памяти, Вы имеете:

A   A
|   |
B   C
 \ /
  D

Это объясняет почему, когда вызов D::foo(), у Вас есть проблема неоднозначности. Но реальный проблема возникает, когда Вы хотите использовать членскую переменную A. Например, скажем, мы имеем:

class A
{
    public :
       foo() ;
       int m_iValue ;
} ;

, Когда Вы попытаетесь получить доступ m_iValue от D, компилятор выступит, потому что в иерархии, он будет видеть два m_iValue, не один. И если Вы измените тот, скажем, B::m_iValue (который является A::m_iValue родитель [1 110]), [то 1111] не будет изменен (который является A::m_iValue родитель [1 113]).

Это - то, куда виртуальное наследование происходит удобное, как с ним, Вы возвратитесь к истинному ромбовидному расположению, с не только один foo() метод только, но также и один и только один m_iValue.

, Что могло пойти не так, как надо?

Вообразите:

  • A имеет некоторую основную характеристику.
  • B добавляет к нему, некоторый прохладный массив данных (например)
  • C добавляет к нему некоторую замечательную опцию как шаблон "наблюдатель" (например, на [1 119]).
  • D наследовался от [1 121] и C, и таким образом от [1 123].

С нормальным наследованием, изменяя m_iValue от [1 125] неоднозначно, и это должно быть разрешено. Даже если это, существует два m_iValues внутреннее D, таким образом, необходимо помнить, что и обновляют два одновременно.

С виртуальным наследованием, изменяя m_iValue от [1 129] в порядке... Но... Скажем, то, что Вы имеете D. Через C интерфейс, Вы присоединили наблюдателя. И через B интерфейс, Вы обновляете прохладный массив, который имеет побочный эффект прямого изменения m_iValue...

, Поскольку изменение [1 134] сделано непосредственно (не используя виртуальный метод доступа), наблюдателя, "слушающего" до [1 135], не позвонят, потому что код, реализовывая слушание находится в [1 136], и B не знает об этом...

Заключение

, Если у Вас есть ромб в Вашей иерархии, это означает, что у Вас есть 95%, чтобы сделать что-то не так с упомянутой иерархией.

13
задан Sébastien Ros - MSFT 9 August 2009 в 14:39
поделиться

4 ответа

Да, пользовательские операторы вызываются с помощью отражения (у них есть специальные имена, такие как op_Addition), но System.Int32 не определяет их, поскольку основные, встроенные типы обрабатываются непосредственно кодами операций IL, например add , а не вызовы методов.

7
ответ дан 1 December 2019 в 22:58
поделиться

Что именно вы хотите сделать? Работа с различными значениями операторов (примитивными (сопоставленными с конкретными инструкциями IL), настраиваемыми (сопоставленными со статическими методами) и поднятыми (предоставляемыми компилятором в качестве шаблона)) делает это болезненным. Если вы просто хотите использовать операторы, то можно написать код, обеспечивающий поддержку операторов через дженерики . У меня есть код для этого, который находится в свободном доступе в MiscUtil ( описание и примеры ).


В качестве нетипизированного примера (обратите внимание, что это не очень эффективно, но работает ):

object x = 123, y = 345; // now forget that we know that these are ints...
object result = Expression.Lambda<Func<object>>(
    Expression.Convert(Expression.Add(
        Expression.Constant(x), Expression.Constant(y)),
    typeof(object))).Compile()();
4
ответ дан 1 December 2019 в 22:58
поделиться

Было бы очень неэффективно, если бы для добавления или сравнения двух целых чисел требовался вызов метода, поэтому эти простые операции с основными типами генерируются кодом, как описано в другом ответе, и не могут быть вызваны с помощью отражения. Один интересный встроенный тип значения - это decimal (или System.Decimal ). Эта структура поддерживает буквальные значения в C #, но ведет себя во многом как реальный тип значения и предоставляет множество операторов, которые можно вызывать через отражение.

любопытно, что вы можете использовать Reflector для просмотра всех элементов, представленных System.Int32 .

0
ответ дан 1 December 2019 в 22:58
поделиться

Здесь есть хорошие ответы, так что просто чтобы добавить еще не упомянутое:

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

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

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

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