Ошибка .NET: ldtoken созданного универсального метода

Я пытаюсь получить метод ldtoken IL для загрузки универсального экземпляра универсального метода в универсальном классе (скажем, List.ConvertAll<TOutput>):

ldtoken method instance
    class [mscorlib]System.Collections.Generic.List`1<!!0> 
    [mscorlib]System.Collections.Generic.List`1::ConvertAll<string>(
        class [mscorlib]System.Converter`2<!0,!!0>)

Это приводит к исключению:

Необработанное исключение: System.TypeLoadException: не удалось загрузить тип «System.Collections.Generic.List`1» из сборки «TestAssembly, версия = 0.0.0.0, культура = нейтральная, PublicKeyToken = null».

Он ищет в моей тестовой сборке System.Collections.Generic.List, хотя он явно объявлен в mscorlib!

Однако загрузка неэкземплярного токена метода работает:

ldtoken method instance
    class [mscorlib]System.Collections.Generic.List`1<!!0> 
    [mscorlib]System.Collections.Generic.List`1::ConvertAll<[1]>(
        class [mscorlib]System.Converter`2<!0,!!0>)

Общий метод в неуниверсальном классе работает:

ldtoken method void [mscorlib]System.Array::Sort<object>(!!0[])
ldtoken method void [mscorlib]System.Array::Sort<[1]>(!!0[])

В чем дело? Это ошибка в .NET? (Я воспроизвел это на v2 и v4 CLR)


person thecoop    schedule 29.05.2012    source источник
comment
Должен ли ваш преобразователь быть чем-то вроде class [mscorlib]System.Converter`2<!!0,string>?   -  person svick    schedule 29.05.2012
comment
Нет, потому что, помимо фактического универсального экземпляра, сигнатуры методов указываются в неконкретизированном контексте.   -  person thecoop    schedule 29.05.2012
comment
Та же ошибка - TypeLoadException с тем же сообщением   -  person thecoop    schedule 29.05.2012
comment
Разве вам не нужен общий экземпляр самого типа? То есть я ожидал что-то вроде... System.Collections.Generic.List`1‹string›::ConvertAll‹string›(...).   -  person kvb    schedule 29.05.2012
comment
@kvb: это недопустимый синтаксис il   -  person thecoop    schedule 30.05.2012


Ответы (1)


Как я уже упоминал в комментарии, я думаю, вам нужно создать экземпляр универсального типа (т.е. нет такого типа, как System.Collections.Generic.List`1 - только System.Collections.Generic.List`1<object> и т. д.).

Поэкспериментировав с System.Reflection.Emit, можно сделать вывод, что можно использовать ldtoken с экземпляром или без экземпляра метода для экземпляра универсального типа:

ldtoken method instance 
    class [mscorlib]System.Collections.Generic.List`1<!!0> 
    class [mscorlib]System.Collections.Generic.List`1<object>::ConvertAll<[1]>(
        class [mscorlib]System.Converter`2<!0,!!0>)
ldtoken method instance 
    class [mscorlib]System.Collections.Generic.List`1<!!0> 
    class [mscorlib]System.Collections.Generic.List`1<object>::ConvertAll<string>(
        class [mscorlib]System.Converter`2<!0,!!0>)

но не с неустановленным универсальным типом. Раздел II, раздел 9.4 спецификации ECMA CLI гласит, что

CLI не поддерживает частичное создание универсальных типов. И универсальные типы не должны отображаться без экземпляров нигде в больших двоичных объектах подписи метаданных.

так что, возможно, это неудивительно - похоже, нет никакого способа использовать ldtoken с эквивалентом typeof(List<>).GetMethod("ConvertAll").

person kvb    schedule 29.05.2012
comment
Нет, это недопустимый синтаксис IL. Вы не можете указать экземпляр типа и экземпляр метода в одном и том же токене. - person thecoop; 30.05.2012
comment
@thecoop - я не знаю, что вам сказать, но это то, что выводит ildasm, когда (рабочая) сборка, созданная Reflection.Emit, разбирается, и ilasm, кажется, принимает ее без проблем при повторной сборке. Как еще можно указать конкретный тип? - person kvb; 30.05.2012
comment
@thecoop - Хотя я использую бета-версию .NET 4.5, возможно, поведение предыдущих версий .NET отличается? - person kvb; 30.05.2012
comment
@thecoop - я получаю то же самое, когда компилирую Expression<Func<List<object>, Converter<object,string>, List<string>>> f = (l,c) => l.ConvertAll(c); на C#, ориентируясь на .NET 3.5. - person kvb; 30.05.2012
comment
С помощью перегрузки GetMethodFromHandle(RuntimeMethodHandle, RuntimeTypeHandle). Я попытался скомпилировать метод в IL, состоящий только из этой инструкции, и ilasm завершается с ошибкой синтаксиса в '‹' экземпляра типа. - person thecoop; 30.05.2012
comment
@thecoop - Что вы получите от ildasm, если скомпилируете код C# из моего предыдущего комментария? ilasm отлично работает для меня с любым из ldtokens, которые я написал в своем ответе (и ret) в методе. - person kvb; 30.05.2012