【问题标题】:How to prevent C# compiler from removing internal constructor如何防止 C# 编译器删除内部构造函数
【发布时间】:2011-11-05 09:17:08
【问题描述】:

我有一个带有 2 个构造函数的公共类:默认(不带参数)是内部的,另一个是公共的。 默认构造函数使用一些默认值调用另一个构造函数。

我使用反射调用内部构造函数,因此它不会在程序集中的任何地方静态使用(仅通过反射)。

当我进行反射调用时,我得到:

System.MissingMethodException
    Message=No parameterless constructor defined for this object.

我知道两种解决方法:

  1. 将构造函数公开(但我不希望此程序集的用户使用它)。
  2. 从一些公共方法调用构造函数(我有很多这样的类,所以我不想写很多这种丑陋无用的代码)。

这个问题有更好的解决方案吗?

值得一提的是,如果默认构造函数是公共的,我不会得到那个异常。

谢谢,

波阿斯。

【问题讨论】:

  • C# 编译器不会删除代码。使用 ildasm.exe 说服自己。
  • 向我们展示导致此异常的代码。您是否在反射调用中提供了正确的 BindingFlags
  • 谢谢,我不知道 ildasm。我可以在那里找到默认构造函数,但我仍然得到一个 MissingMethodException。如果它是公开的,我不明白。
  • 你究竟是什么时候收到这个错误的?
  • 当我使用反射调用时。

标签: c# reflection compiler-optimization internal


【解决方案1】:

构造函数没有被删除,可能在搜索你的构造函数时你应该指定标志BindingFlag.NonPublic

    class xxx
    {
        private xxx() :
            this(10)
        {
        }

        public xxx(int value)
        {
            Console.WriteLine(value);
        }
    }

    static void Main(string[] args)
    {
        Activator.CreateInstance(typeof(xxx), true);
        Console.ReadLine();
    }

Activator.CreateInstance 有一个带有布尔值的重载,您可以在其中指定是否要调用非公共构造函数。

public static Object CreateInstance(
    Type type,
    bool nonPublic
)

Activator.CreateInstance(type, true) 将调用构造函数,无论它是 public 还是 private\internal\protected。

【讨论】:

  • 谢谢。确实如此。我还有其他具有公共默认构造函数的此类。我尝试设置 (BindingFlags.NonPublic | BindingFlags.Public) 但它只找到 NonPublic 的。
  • Activator.CreateInstance(type, true) 无论是公共的还是非公共的都会调用构造函数。
【解决方案2】:

C# 编译器不会为您删除任何构造函数。在 Reflector 中打开程序集,我相信你会看到你创建的构造函数。

我认为您用于查找构造函数的反射代码更有可能不包括BindingFlags.NonPublic。示例代码来展示它如何 工作:

using System;
using System.Reflection;

class Foo
{
    internal Foo()
    {
        Console.WriteLine("Foo constructor");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var ctor = typeof(Foo).GetConstructor
            (BindingFlags.NonPublic |
             BindingFlags.Public |
             BindingFlags.Instance,
             binder: null,
             types: new Type[0],
             modifiers: null);
        ctor.Invoke(null);
    }
}

编辑:要将绑定标志传递给Activator.CreateInstance,您需要使用不同的重载,如下所示:

Activator.CreateInstance(typeof(Foo),                                 
                         BindingFlags.NonPublic |
                         BindingFlags.Public |
                         BindingFlags.Instance,
                         binder: null,
                         args: null,
                         culture: null);

(或者您可以使用 cmets 中提到的CreateInstance(type, true)。)

【讨论】:

  • 谢谢。但是,当我使用 Activator.CreateInstance(type, BindingFlags.NonPublic | BindingFlags.Public) 时,它只找到 NonPublic 并且没有找到具有公共类型的公共构造函数。
  • @brickner:我相信你实际上只是调用了错误的 Activator.CreateInstance 重载,它试图将绑定标志作为参数传递。例子来了...
  • @brickner:从这个问题中学到一件事:不要假设您知道发生了什么(编译器删除了构造函数),而是发布一个简短但完整的程序来演示该问题。这样我们就可以更轻松地找出问题所在并帮助您纠正问题。
猜你喜欢
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多