不调用构造函数创建对象实例?

时间:2008-11-17 19:24:56

标签: c#

在C#中,有没有办法在不调用构造函数的情况下实例化类的实例?

假设该类是公共的,并在第三方库中定义,构造函数是内部的。我想这样做的原因很复杂,但知道是否有可能使用某种C#hackery会很有帮助。

注意:我特别不想调用任何构造函数,因此使用反射访问内部构造函数不是一种选择。

11 个答案:

答案 0 :(得分:80)

我没有尝试过这个,但在反序列化过程中使用了一个名为FormatterServices.GetUninitializedObject的方法。

MSDN的评论说:

  

因为对象的新实例   被初始化为零,没有   构造函数运行,对象可能   不代表被视为的国家   由该对象有效。

答案 1 :(得分:10)

实际上,听起来他们将构造函数设置为内部,因此您无法实例化它。它可能有建造者或工厂方法。

查看这些文章:

Preventing Third Party Derivation: Part 1

Preventing Third Party Derivation: Part 2

他们解释了这个推理。

答案 2 :(得分:6)

与许多人认为的相反,构造函数根本没有与对象的实例化有很大关系(相当误导性的术语)。构造函数是一种特殊方法,可以在对象实例化之后调用,以允许该对象正确初始化自身。在C ++对象实例化中为对象分配内存,在.NET和Java中,它根据字段的类型(0,null,false等)分配和预初始化为默认值。然后运行时调用构造函数。新运算符将这两个单独的操作封装到看似单个操作的操作中。 如果不使用构造函数就无法创建实例,那么反序列化在.NET中永远不会有效。也就是说,所谓的ConstructorInfo类型在调用其Invoke(...)方法时充当新的运算符和构造函数。

答案 3 :(得分:0)

有可能通过反射访问构造函数并像这样调用它(但我不确定它是否会起作用,因为构造函数是内部的 - 你必须测试它)。 否则,据我所知,如果不调用构造函数,就无法创建对象。

答案 4 :(得分:0)

编辑:你更新了你的问题,你想构建一个没有构造函数的类。或者调用默认的“空构造函数”。

这是不可能的,因为如果已经指定了一个默认构造函数,编译器将不会生成默认构造函数。但是,为了读者的利益,这里是如何获得内部,受保护或私有构造函数:

假设你的班级名为Foo:

using System.Reflection;

// If the constructor takes arguments, otherwise pass these as null
Type[] pTypes = new Type[1];
pTypes[0] = typeof(object);    
object[] argList = new object[1];
argList[0] = constructorArgs;

ConstructorInfo c = typeof(Foo).GetConstructor
    (BindingFlags.NonPublic |
     BindingFlags.Instance,
     null,
     pTypes,
     null);

Foo foo = 
    (Foo) c.Invoke(BindingFlags.NonPublic,
                   null, 
                   argList, 
                   Application.CurrentCulture);

丑陋,但有效。

当然,可能有一个完全正当的理由将构造函数标记为内部构造函数,因此在滥用该类之前,应该通过反射来真正考虑所需内容。

答案 5 :(得分:0)

您必须调用构造函数来创建对象。如果没有你喜欢的,也许你可以使用字节码重写库,如Mono项目的Cecil。它适用于Windows和Linux。从我看到的一些演示中,它看起来很酷。您可以更改方法和各种疯狂内容的保护级别。

答案 6 :(得分:0)

如果类(及其引用的对象类)是Serializable,则可以通过使用BinaryFormatter进行序列化来创建深层副本,该BinaryFormatter输出到MemoryStream(创建字节数组byte []),然后反序列化。见the answers to this question on converting an object to a byte array。 (但请注意 - 保存字节数组以便以后/其他地方使用可能不起作用.IOW不会将字节数组保存到文件或其他持久形式。)

答案 7 :(得分:-1)

请参阅System.Activator.CreateInstance函数。

答案 8 :(得分:-1)

您要求做的是违反开发托管编程的理念。 .Net Framework和C#的构建原则是,只要有可能,对象就应该从其底层内存中抽象出来。对象是对象,而不是结构化的字节数组。这就是为什么你不能无条件地将对象转换为void指针的原因。当对象从其底层内存中抽象出来时,建议在不调用构造函数的情况下存在对象实例是完全无效的。

也就是说,.Net框架已经让步于实际上,对象实际上是在内存中表示的事实让步了。通过一些创造性,可以在不调用其初始值设定项的情况下实例化值类型。但是,如果您觉得需要这样做,那么您可能做错了。

答案 9 :(得分:-1)

我注意到了这个主题的“死亡”,但仅仅是为了澄清其他读者,并提出一个可能在发布问题时无法做出的最终答案。在这里。

似乎您可以通过为其属性赋值来实例化一个类而不使用它的构造函数。以下是MSDN中此类实例化http://msdn.microsoft.com/en-us/library/bb397680.aspx的操作方法的地址。

这似乎是一种不为人所熟知的技术,因为我在CodeProject的一篇文章中遇到它然后用谷歌搜索它并且没有找到任何关于它的信息,后来又访问了MSDN主页,并且有一篇帖子链接了我到那个确切的主题。因此,它似乎是一个未知主题而不是新主题,因为CodeProject帖子上的日期是2008年5月。

希望这可以帮助其他人谷歌这个并遇到这个问题。

答案 10 :(得分:-3)

这里没有人明确澄清“无法做到”的含义。

构造函数创建对象的内容。你的问题类似于“我怎样才能建造一座沙堡而不像城堡一样塑造它?”你不能 - 所有你将拥有的是一堆沙子。

您可以做的最接近的事情是分配一个与您的对象大小相同的内存块:

byte[] fakeObject = new byte[sizeof(myStruct)];

(注意:即使只能在MyStruct中使用,也是值类型)