Методы расширения, определенные для типов значений, не могут использоваться для создания делегатов. Почему нет?

Обратите внимание, что (.|\n)* может быть менее эффективным, чем (например) [\s\S]* (если регулярные выражения вашего языка поддерживают такие escape-последовательности), а не поиск того, как указать модификатор, который делает. также соответствуют новостям. Или вы можете пойти с альтернативами POSIXy, такими как [[:space:][:^space:]]*.

30
задан Soner Gönül 27 June 2013 в 14:29
поделиться

2 ответа

В ответ на мой другой ответ Эрик Смит правильно отмечает:

«... потому что это потребует неявной упаковки параметра типа получателя ...». Что в любом случае произойдет, если вы сделаете что-то вроде этого: Func f = 5.ToString; Что совершенно законно.

Размышляя об этом, я пришел к новому ответу. Примерьте это для размера:

Обычные методы «экземпляра» в структурах принимают на уровне CIL «управляемый указатель» (тип & ) в качестве параметра приемника. Это необходимо для того, чтобы методы экземпляра в структурах могли назначаться полям структуры. См. Раздел II, раздел 13.3 .

Точно так же методы экземпляра классов принимают «ссылку на объект» (тип O ) в качестве параметра приемника (разница в том, что это указатель на управляемую кучу, и должны отслеживаться для GC).

Поскольку как CIL & , так и O s могут (и реализуются) реализованы с помощью указателей, для делегата все очень сложно реализация. Независимо от того, захватывает ли делегат статический метод, метод экземпляра класса или метод экземпляра структуры, все, что ему нужно сделать, это передать указатель на его _target первому аргументу функции.

Но сценарий, который мы обсуждаем, разрушает это. Статический метод расширения, принимающий int в качестве первого аргумента, требует аргумента CIL типа int32 (см. Раздел III, раздел 1.1.1). Вот где все идет наперекосяк. Я не вижу причин, по которым реализация делегатов не могла понять, что это происходит (например, путем проверки метаданных, связанных с захватываемым MethodInfo) и генерирует преобразователь, который распаковывает _target и передает его в качестве первого аргумента, но этого не требуется для делегатов классическим методам экземпляра на структур, поскольку они все равно ожидают указатель и не появляются (судя по примеру в моем предыдущем неправильном ответе) для реализации. Очевидно, конкретный рассматриваемый тип значения будет контролировать точную природу требуемого преобразователя.

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

18
ответ дан 27 November 2019 в 22:49
поделиться

РЕДАКТИРОВАТЬ 2 Я больше не верю этому ответу, но я оставил его здесь, чтобы тема по-прежнему имела смысл и чтобы люди поняли, почему это неверно. См. Другой мой ответ на этот вопрос.

Исходный

Потому что это потребует неявной упаковки параметра получателя типа значения (поскольку поле _target в типе System.Delegate, которое содержит параметр получателя, имеет тип System.Object), что могло бы привести к странному поведению псевдонима, если бы вы этого не ожидали.

EDIT

Здесь происходит что-то еще. Я запустил этот пример программы:

class Program
{
    public static int Combine(int a, int b)
    {
        return a + b;
    }

    static void Main(string[] args)
    {
        var combineMethod = typeof(Program).GetMethod("Combine");
        var add4 = Delegate.CreateDelegate(
                              typeof(Converter<int, int>),
                              4,
                              combineMethod) as Converter<int, int>;

        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(add4(i));
        }
        Console.ReadLine();
    }
}

и получил исключение ArgumentException: «Ошибка привязки к целевому методу». при вызове CreateDelegate. Я не уверен, почему, и поскольку соответствующий метод - метод внутреннего вызова , Reflector не очень помогает. Документация для CreateDelegate также не сильно помогла. Я уверен, что это как-то связано с упаковкой приемника, может быть, кто-нибудь, знакомый с источником Rotor, может помочь объяснить, почему?

2
ответ дан 27 November 2019 в 22:49
поделиться