MissingMethodException при применении параметров универсального типа к методу, который возвращает универсальный параметр - PullRequest
3 голосов
/ 01 января 2012

У меня есть метод DynamicInvoke, который выглядит следующим образом:

public static object InvokeDynamic(Delegate d, object[] args)
{
    Type[] tparams = d.Method.DeclaringType.GetGenericArguments()
                        .Concat(d.Method.GetGenericArguments())
                        .ToArray();
    Type dt = d.GetType().DeclaringType;
    if (dt.ContainsGenericParameters)
        dt = dt.MakeGenericType(tparams);
    IDirectInvoke di = dt.GetConstructor(Type.EmptyTypes).Invoke(null) as IDirectInvoke;
    object o = di.Invoke(d.Method, d.Target, args);
    return o;
}

Он используется в следующем контексте (и да, это программно сгенерированный код с использованием Mono.Cecil и обратный с использованием ILSpy):

[Processed, Distributed]
[Serializable]
public class GenericsTest<A, B> : ITransparent, ISerializable where A : new() where B : ITest
{
    private class Method3__InvokeDirect3<C> : IDirectInvoke
    {
        [CompilerGenerated]
        public delegate C Method3__DistributedDelegate4();
        public object Invoke(MethodInfo method, object instance, object[] parameters)
        {
            GenericsTest<A, B>.Method3__InvokeDirect3<C>.Method3__DistributedDelegate4 method3__DistributedDelegate = (GenericsTest<A, B>.Method3__InvokeDirect3<C>.Method3__DistributedDelegate4)Delegate.CreateDelegate(typeof(GenericsTest<A, B>.Method3__InvokeDirect3<C>.Method3__DistributedDelegate4), instance, method);
            return method3__DistributedDelegate.Invoke();
        }
    }
    public C Method3<C>()
    {
        MulticastDelegate d = new GenericsTest<A, B>.Method3__InvokeDirect3<C>.Method3__DistributedDelegate4(this.Method3__Distributed0<C>);
        object[] args = new object[0];
        return (C)DpmEntrypoint.Invoke(d, args);
    }
    [CompilerGenerated]
    private C Method3__Distributed0<C>()
    {
        return default(C);
    }
}

Теперь код работает правильно, если либо a) GenericsTest не имеет общих параметров, либо b) метод не имеет общих параметров (и у меня есть другие классы и методы, которые это проверяют).Проблема возникает только тогда, когда класс и методы содержат общие параметры.

Когда вызывается di.Invoke, я получаю следующее исключение:

System.MissingMethodException was unhandled
  Message="Method not found: '**UNKNOWN TYPE** Method3__DistributedDelegate4.Invoke()'."
  Source="Examples.ServerClient"
  StackTrace:
       at Examples.ServerClient.GenericsTest`2.Method3__InvokeDirect3`1.Invoke(MethodInfo method, Object instance, Object[] parameters)
       at Process4.Providers.DpmEntrypoint.InvokeDynamic(Delegate d, Object[] args) in C:\Server Storage\Projects\Redpoint\Dx\Process4\Providers\Dpm.cs:line 249
       at Process4.Providers.DpmEntrypoint.Invoke(Delegate d, Object[] args) in C:\Server Storage\Projects\Redpoint\Dx\Process4\Providers\Dpm.cs:line 359
       at Examples.ServerClient.GenericsTest`2.Method3[C]()
       at Examples.ServerClient.Program.GenericsTest() in C:\Server Storage\Projects\Redpoint\Dx\Examples.ServerClient\Program.cs:line 76
       at Examples.ServerClient.Program.Main(String[] args) in C:\Server Storage\Projects\Redpoint\Dx\Examples.ServerClient\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

Учитывая, что я проверилрезультаты в ILSpy, IL и метаданных функционально эквивалентны результатам, сгенерированным самим компилятором C # (проверено путем копирования кода в файл .cs и его компиляции), теперь я думаю, что это использование метода Invoke во время выполненияэто вызывает эту проблему.

Одним из странных эффектов является то, что конструктор вызывается успешно, а Visual Studio правильно сообщает типы при проверке вновь созданного объекта IDirectInvoke (он вызывает только исключение при вызове Invoke), и все же какотмечалось ранее, что IL для Invoke идентичен тому, что генерирует C #.

Кто-нибудь знает, в чем проблема может быть в этом случае?

РЕДАКТИРОВАТЬ: Еще одна вещь,это происходит только в методах, которые напрямую возвращают универсальный параметр, назначенный методу (поэтомуне происходит, если метод возвращает A, B или другой экземпляр универсального типа, который содержит параметры A, B или C;в этом случае это происходит потому, что метод напрямую возвращает объект типа C).

...