使用.Net Standard通用参数在mscorlib通用类型上调用DynamicMethod会导致MissingMethodException

时间:2018-08-02 10:24:38

标签: c# .net generics dynamic .net-standard-2.0

那么这是怎么回事?

这是背景故事。我正在尝试将.net标准库集成到.net框架产品中。该.net框架产品正在使用旧的Microsoft.Practices框架,该框架使用ObjectBuilder作为服务容器。

ObjectBuilder不能做的现代IoC容器可以做的一件事是处理同一服务类型的多个实现,并在请求时注入该服务类型的IEnumerable 。为了解决这个问题,我将手动添加一个List ,并在添加到对象生成器时手动添加每个实现。

ObjectBuilder在Microsoft.Practices的WebClientSoftwareFactory中使用时,使用IL构造容器的对象并将依赖项注入属性。因此,即使您添加一个单例实例,它仍然会尝试使用IL注入实例的属性。

尝试将.Net Standard类型的List 添加到ObjectBuilder时发生错误。我已经能够在控制台应用程序中复制导致错误的原因。

这是在.net Framework 4.7.2上运行的控制台应用程序

namespace ILTest
{
    class Program
    {
        delegate string Echo(string value);

        static void Main(string[] args)
        {
            Console.WindowWidth = Console.WindowWidth * 2;

            EchoOn("1324");
            EchoOn(new List<string>());
            EchoOn(new NetStandardType());
            EchoOn(new List<NetStandardType>()); // this line fails
            EchoOn(new GenericNetStandardType<string>());
            EchoOn(new GenericNetStandardType<NetStandardType>());

            Console.ReadLine();
        }

        static void EchoOn<T>(T obj)
        {
            var type = typeof(T);
            var value = Guid.NewGuid().ToString();
            var echo = CreateEchoMethodOn(obj);
            try
            {
                var echoed = echo(value);
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine($"Successful il on {type.FullName}");
            }
            catch(Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine($"Failed il on {type.FullName}");
                Console.WriteLine(ex);
            }
        }

        static Echo CreateEchoMethodOn(object obj)
        {
            var type = obj.GetType();
            var method = new DynamicMethod($"Echo_{type.FullName}", typeof(string), new[] { typeof(string) }, type);
            var il = method.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ret);
            return (Echo)method.CreateDelegate(typeof(Echo));
        }
    }
}

这些是.net标准2.0库中的类

namespace StandardLib
{
    public class NetStandardType
    {
    }

    public class GenericNetStandardType<T>
    {
    }
}

除List 上的所有DynamicMethods均成功。那会因为MissingMethodException而失败。

  • 字符串
    • .net框架类型
    • DynamicMethod成功
  • 列表
    • .net框架通用类型
    • .net框架通用参数
    • DynamicMethod成功
  • NetStandardType
    • .net标准类型
    • DynamicMethod成功
  • 列表
    • .net框架通用类型
    • .net标准通用参数
    • DynamicMethod失败
  • GenericNetStandardType <字符串>
    • .net标准通用类型
    • .net框架通用参数
    • DynamicMethod成功
  • GenericNetStandardType
    • .net标准通用类型
    • .net标准通用参数
    • DynamicMethod成功

那么,这又是怎么回事?是.net框架中DynamicMethod中的错误?

1 个答案:

答案 0 :(得分:0)

我相信您是由于Code Access Security和透明度规则的复杂工作方式而看到这种行为的。

当您使用列表作为DynamicMethod的类型所有者时,您正在指示运行时使用该类型的CAS选项。当您使用用户定义的类型(在.NET 4上)时,您的类型成员实际上被标记为“关键”,而“列表”和“列表”类型上的成员被标记为“透明”。

由于您尝试从“透明”类型调用“关键”代码,因此出现了所提到的错误。

我相信您可以通过使用以下属性标记具有您的用户类型的程序集来解决此问题:

[assembly: System.Security.SecurityTransparent]

尽管该方法可行,但很难说这是否会带来任何意想不到的后果。我相信这将取决于您的情况。请查看this document以获取更多信息。