如何调用只有私有构造函数的类open in new window

当我试用ObjectSpaces时,ObjectSpaces竟然能够调用只有私有构造函数的类。例如:

Class A
{
    private A() {}
}

ObjectSpaces能够创建A的实例,我刚看到的时候,吃了一惊,呵呵…… 后来,借助Reflector分析整理学会了此技巧。

你不能通过Reflection直接创建只有私有构造函数的类,但是你可以通过一些偏门技巧绕过此限制。

其大概思路这样的:

private CreateInstanceDelegate<T> BuildDelegate<T>()
{
    Type type = typeof(T);

    AssemblyName assemblyName = new AssemblyName();
    assemblyName.Name = "System.Data.ObjectSpaces.Dynamic";

    AssemblyBuilder assemblyBuilder 
    = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

    Module module 
    = assemblyBuilder.DefineDynamicModule("WebData", "DynamicAssembly.dll", true);

    Type[] paramTypeArray = new Type[] {};
    Type rtnType = type;
    String methodName = "call_privateCtor";
    bool skipVisibility = true;

    DynamicMethod method = new DynamicMethod(
    methodName,
    rtnType, 
    paramTypeArray, 
    module,
    skipVisibility
    );

    ConstructorInfo ctor = type.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
    null,
    new Type[0],
    null
    );

    ILGenerator ilGen = method.GetILGenerator();
    ilGen.Emit(OpCodes.Newobj, ctor);
    ilGen.Emit(OpCodes.Ret);

以上是思路,我们也来写一段代码,让其能够调用缺省构造函数创建对象实例,具体代码:

第一步, 定义一个Delegate:

public delegate T CreateInstanceDelegate<T>();

第二步,定义构建Delegate的方法,关键在此:

private CreateInstanceDelegate<T> BuildDelegate<T>()
{
    Type type = typeof(T);

    AssemblyName assemblyName = new AssemblyName();
    assemblyName.Name = "System.Data.ObjectSpaces.Dynamic";

    AssemblyBuilder assemblyBuilder 
    = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

    Module module 
    = assemblyBuilder.DefineDynamicModule("WebData", "DynamicAssembly.dll", true);

    Type[] paramTypeArray = new Type[] {};
    Type rtnType = type;
    String methodName = "call_privateCtor";
    bool skipVisibility = true;

    DynamicMethod method = new DynamicMethod(
    methodName,
    rtnType, 
    paramTypeArray, 
    module,
    skipVisibility
    );

    ConstructorInfo ctor = type.GetConstructor(
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
    null,
    new Type[0],
    null
    );

    ILGenerator ilGen = method.GetILGenerator();
    ilGen.Emit(OpCodes.Newobj, ctor);
    ilGen.Emit(OpCodes.Ret);

    return (CreateInstanceDelegate<T>) method.CreateDelegate(typeof(CreateInstanceDelegate<T>));
}

第三步,定义创建实例的方法:

public T CreateInstance<T>()
{
    CreateInstanceDelegate<T> createInstDelegate = BuildDelegate<T>();
    return createInstDelegate();
}

第四步,如此使用:

定义一个私有缺省构造函数的类

class A
{
    private A() {}
}

创建实例的代码:

A a = CreateInstance<A>();
Console.WriteLine("create A instance");

2004-09-10 10:59dddddd 回复 引用

" 如何调用只有私有构造函数的类 "

只论技术而言,挺好,但从另外一个方面,你要完成这个是不是说明设计做的不好?

2004-09-10 11:17玉明熙 回复 引用

这是一段Java5的代码? 另外,用Java的反射很容易就能访问私有变量和私有函数,要生成A只需要调用Constructor 的setAccessible函数就可以访问A的私有构造函数了啊。

2004-09-10 16:02玉明熙 回复 引用

-_-`原来是C#的。

2004-09-10 21:12温少 回复 引用

@dddddd 你可以了解一下ObjectSpaces的实现,可能你就不认为这是一个设计问题?

2008-02-02 11:50Saiman 回复 引用

虽然我也常用反射发出, 但是像你这种做法明显是多此一举... 究竟有什么好惊讶的呢? 不就是创建只有私有构造函数的类??? 一句就搞定: A a = Activator.CreateInstance(typeof(A), true);

2008-04-12 16:13dddd 回复 引用

dddd我支持

Contributors: FHL