【问题标题】:Instantiating Internal class with private constructor使用私有构造函数实例化内部类
【发布时间】:2017-09-08 00:24:25
【问题描述】:

我正在尝试使用反射来创建类的实例。但它是密封的内部并具有私有构造函数。我想知道如何初始化它,作为框架的一部分,我只能使用反射将其取出?

internal sealed class ABC
{
    private ABC(string password){}
    public static ABC Create(string password){};
}

添加: System.ServiceModel.Channels.SelfSignedCertificate 是我尝试使用的内部类

【问题讨论】:

  • 是调用私有构造函数还是调用静态Create方法?
  • 是上述结构的框架内部类。我想使用构造函数/静态方法创建类的实例,然后使用 MethodInfo 使用类中的方法。 object mc = assembly.CreateInstance( ----

标签: c#


【解决方案1】:

编辑:我没有注意到您提到您尝试初始化的类型是 .NET 框架的一部分。我以为是你自己的类型之一,只是从别处引用的。

我强烈建议您不要尝试这样做。 Microsoft 完全可以在框架版本之间更改或删除内部类 - 如果您依赖这样的实现细节,您的代码将非常脆弱。

更改您的设计以避免需要这样做。


原答案:

是的,你必须使用反射——像这样:

using System;
using System.Reflection;

internal sealed class ABC
{
    private ABC(string password)
    {
        Console.WriteLine("Constructor called");
    }
}

public class Test
{
    static void Main()
    {
        ConstructorInfo ctor = typeof(ABC).GetConstructors
            (BindingFlags.Instance | BindingFlags.NonPublic)[0];

        ABC abc = (ABC) ctor.Invoke(new object[] { "test" });
    }
}

请注意,以这种方式违反访问修饰符需要ReflectionPermissionFlag.MemberAccess 权限。如果你知道会有一个名为Create 的静态方法,你最好通过反射调用that

using System;
using System.Reflection;

internal sealed class ABC
{
    private ABC(string password)
    {
        Console.WriteLine("Constructor called");
    }

    public static ABC Create(string password)
    {
        return new ABC(password);
    }
}

public class Test
{
    static void Main()
    {
        MethodInfo method = typeof(ABC).GetMethod("Create",
            BindingFlags.Static | BindingFlags.Public);

        ABC abc = (ABC) method.Invoke(null, new object[]{"test"});
    }
}

【讨论】:

  • 如果 ABC 类型在另一个程序集中是内部的,他将需要通过其全名获取类型。
  • 感谢大家的cmets。我会找到另一种方法来做到这一点。 MS可以改变它是一个有效的点!再次感谢
【解决方案2】:

首先,它是内部的事实意味着你不应该做你想做的事。

你应该认真地尝试找到一条替代路线来实现你想要完成的目标。

很遗憾,你没有告诉我们你想要完成什么,只告诉我们你认为你想做的下一步,所以这就是我可以帮助你的。

这段代码可以工作,并访问公共静态方法:

Type t = typeof(SomeOtherTypeInSameAssembly)
    .Assembly.GetType("ClassLibrary1.ABC");
MethodInfo method = t.GetMethod("Create",
    BindingFlags.Public | BindingFlags.Static, null,
    new Type[] { typeof(String) },
    new ParameterModifier[0]);
Object o = method.Invoke(null, new Object[] { "test" });

请注意,这依赖于访问同一程序集中的另一种类型,即公共类型。如果没有,则需要获取包含该类型的 Assembly 对象。

【讨论】:

  • First of all, the very fact that it is internal means you're not supposed to be doing what you want to do. 进行单元测试但保持类隔离怎么样?
  • 某人需要访问内部类并且知道特定的内部类这一事实实际上表明他们可能足够聪明,可以打开 Reflector 并自行决定这样做是有用还是有益主意。代码就是代码,“内部”修饰符只不过是一种需要规避的 DRM,IMO。
  • @ktutnik:通过单元测试,通常使用InternalsVisibleToAttribute
【解决方案3】:

如果不是您的程序集的internal 并且构造函数标记为private,则程序集的作者正在努力阻止您创建对象。

下面的内容真的很邪恶,因为您依赖于非公共类和方法,这些类和方法可能会在不提前通知的情况下发生变化。

添加:System.ServiceModel.Channels.SelfSignedCertificate 是我尝试使用的 internal

不要这样做。框架可能会在一眨眼之间改变,毁掉你的代码和你所有的辛勤工作。

也就是说,你可以这样做:

MethodInfo method = Type.GetType(assemblyQualifiedName).GetMethod("Create");
ABC o = (ABC)method.Invoke(null, new[] { "test" });

这会调用static 方法Create。另一种选择是

MethodInfo method = Type.GetType(assemblyQualifiedName).GetConstructor(
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null,
                        new[] { typeof(string) },
                        null
                    );
ABC o = (ABC)method.Invoke(new[] { "test" });

它使用反射来加载接受string作为参数的构造函数。

获取程序集限定名称的简单方法是

string name = typeof(somePublicType).Assembly.GetType("Namespace.ABC");

其中somePublicType 是一种公共类型,并且与ABC 在同一个程序集中。

【讨论】:

  • 我无权访问 ABC,因此无法使用 MethodInfo method = typeof(ABC)。我使用反射器并在框架中看到了这个类。我需要使用它。
  • 如果框架设计者希望框架的消费者使用该类,则可以通过其他方式获取对象的实例,而无需求助于这种骇客。
  • @unknown(google):您必须使用程序集限定名称。查看我的编辑。
【解决方案4】:

使用 Activator 类对其进行实例化

Activator.CreateInstance(myType, true);

【讨论】:

  • 错误:无法加载文件或程序集“System.ServiceModel.Channels”或其依赖项之一。系统找不到指定的文件。
  • Activator.CreateInstance(internalType, new object[] {null, null}) 在我的例子中,构造函数需要 2 个参数。它对我有用。
【解决方案5】:

除非是嵌套类,否则不能使用私有构造函数实例化类。

http://msdn.microsoft.com/en-us/library/kcfb85a6%28VS.71%29.aspx

【讨论】:

  • 不正确,如果你有足够的权利,反射一切皆有可能。
  • 但是如果类是内部密封的,你有足够的权限吗?
  • 您可以使用静态方法从类中实例化它。
  • @Matt:如果你有 ReflectionPermissionFlag.MemberAccess,是的。
猜你喜欢
  • 2010-11-15
  • 2016-09-23
  • 1970-01-01
  • 2014-12-12
  • 1970-01-01
  • 2020-06-23
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
相关资源
最近更新 更多