C# 创建对象实例而不调用构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/296584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create object instance without invoking constructor?
提问by Chris Gillum
In C#, is there a way to instantiate an instance of a class without invoking its constructor?
在 C# 中,有没有办法在不调用其构造函数的情况下实例化类的实例?
Assume the class is public and is defined in a 3rd party library and the constructor is internal. The reasons I want to do this are complicated but it would be helpful to know if it's possible using some kind of C# hackery.
假设该类是公共的并且在第 3 方库中定义,并且构造函数是内部的。我想这样做的原因很复杂,但是知道是否可以使用某种 C#hackery 会很有帮助。
NOTE: I specifically do not want to call any constructorso using reflection to access the internal constructor is not an option.
注意:我特别不想调用任何构造函数,因此不能选择使用反射来访问内部构造函数。
采纳答案by Hallgrim
I have not tried this, but there is a method called FormatterServices.GetUninitializedObjectthat is used during deserialization.
我还没有尝试过这个,但是有一个叫做FormatterServices.GetUninitializedObject的方法在反序列化过程中使用。
Remarks from MSDN says:
来自 MSDN 的评论说:
Because the new instance of the object is initialized to zero and no constructors are run, the object might not represent a state that is regarded as valid by that object.
因为对象的新实例被初始化为零并且没有运行构造函数,所以该对象可能不代表被该对象视为有效的状态。
回答by rslite
It might be possible to access the constructor via reflection and invoke it like that (but I'm not sure that it will work since the constructor is internal - you'll have to test it). Otherwise from my knowledge you can't create an object without calling the constructor.
可能可以通过反射访问构造函数并像这样调用它(但我不确定它是否会工作,因为构造函数是内部的 - 你必须测试它)。否则,根据我的知识,您无法在不调用构造函数的情况下创建对象。
回答by Zachary Yates
Actually it sounds like they made the constructor internal just so you can't instantiate it. It may have a builder or factory method.
实际上听起来他们把构造函数放在内部,所以你不能实例化它。它可能有一个构建器或工厂方法。
Check out these articles:
查看这些文章:
Preventing Third Party Derivation: Part 1
Preventing Third Party Derivation: Part 2
they kind of explain the reasoning.
他们有点解释推理。
回答by Cybis
See the System.Activator.CreateInstance function.
请参阅 System.Activator.CreateInstance 函数。
回答by FlySwat
EDIT: You updated your question, you want to construct a class without a constructor. Or call a default "Empty Constructor".
编辑:你更新了你的问题,你想构造一个没有构造函数的类。或者调用默认的“空构造函数”。
This cannot be done, as the compiler will not generate a default constructor if there is already one specified. However, for the benefit of the readers, here is how to get at a internal, protected, or private constructor:
这是不可能的,因为如果已经指定了一个默认构造函数,编译器将不会生成一个默认构造函数。但是,为了读者的利益,这里是如何获得内部、受保护或私有构造函数:
Assuming your class is called Foo:
假设你的班级叫做 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);
Ugly, but works.
丑陋,但有效。
Of course, there may be a perfectly legitimate reason to mark a constructor as internal, so you should really consider the logistics of what you want before you abuse that class by getting at it with reflection.
当然,将构造函数标记为内部构造函数可能有完全合理的理由,因此在通过反射获取该类来滥用该类之前,您应该真正考虑所需内容的逻辑。
回答by Kennet Belenky
What you are asking to do is a violation of the philosophy upon which managed programming was developed. The .Net Framework and C# are built with the principle that, whenever possible, objects should be abstracted away from their underlying memory. Objects are objects, not a structured array of bytes. This is why you can't cast objects to void pointers willy-nilly. When objects are abstracted away from their underlying memory, it is fundamentally invalid to suggest that an object instance can exist without the constructor being invoked.
您要求做的是违反了开发托管编程的哲学。.Net 框架和 C# 的构建原则是,只要有可能,对象应该从它们的底层内存中抽象出来。对象是对象,而不是结构化的字节数组。这就是为什么您不能随意将对象强制转换为 void 指针的原因。当对象从它们的底层内存中抽象出来时,建议一个对象实例可以在没有调用构造函数的情况下存在从根本上是无效的。
That said,the .Net framework has made concessions to the fact that in reality, objects are actually represented in memory. With some creativity, it is possible to instantiate value types without invoking their initializers. However, if you feel you need to do it, you're probably doing things wrong.
也就是说,.Net 框架已经对这样一个事实做出让步,即在现实中,对象实际上是在内存中表示的。有了一些创造力,就可以在不调用它们的初始化程序的情况下实例化值类型。然而,如果你觉得你需要这样做,你可能做错了事情。
回答by James Curran
No one here has quite clarified what is meant by "It can't be done."
这里没有人非常清楚“它不能完成”是什么意思。
The constructor iswhat creates the object. Your question is akin to "How can I build a sand castle without shaping it like a castle?" You can't -- All you will have is a pile of sand.
构造函数是创建对象的东西。你的问题类似于“我怎样才能建造一座沙堡而不把它塑造成一座城堡?” 你不能——你将拥有的只是一堆沙子。
The closest thing you could possible do is to allocate a block of memory the same size as your object:
您可以做的最接近的事情是分配一个与您的对象大小相同的内存块:
byte[] fakeObject = new byte[sizeof(myStruct)];
(NOTE: even that will only work in MyStruct is a value type)
(注意:即使只在 MyStruct 中有效也是值类型)
回答by Sam Corder
You have to call a constructor to create an object. If there are none available to your liking perhaps you could use a byte code rewriting library like the Mono project's Cecil. It works on Windows as well as Linux. From some of the demos I saw, it looked pretty cool. You can change the protection levels of methods and all sorts of crazy stuff.
您必须调用构造函数来创建对象。如果没有您喜欢的可用内容,也许您可以使用像 Mono 项目的 Cecil 这样的字节码重写库。它适用于 Windows 和 Linux。从我看到的一些演示来看,它看起来很酷。您可以更改方法的保护级别和各种疯狂的东西。
回答by Hallgrim
Contrary to what many believe, a constructor hasn't much to do with the instantiation of an object at all (pretty misleading term). A constructor is a special method that can be called after the instantiation of an object to allow that object to properly initialize itself. In C++ object instantiation allocates memory for the object, in .NET and Java it is both allocated and pre-initialized to default values depending on the type of fields (0, null, false etc.). Then the run-time calls the constructor. The new operator encapsulates these two separate actions into what appears to be a single operation. Deserialization could never had worked in .NET if it wasn't possible to create an instance without using a constructor. That said, the so called ConstructorInfo type acts as both a new operator and constructor when calling its Invoke(...) method.
与许多人认为的相反,构造函数与对象的实例化根本没有太大关系(非常具有误导性的术语)。构造函数是一种特殊的方法,可以在对象实例化后调用,以允许该对象正确初始化自身。在 C++ 对象实例化中为对象分配内存,在 .NET 和 Java 中,它根据字段的类型(0、null、false 等)分配并预初始化为默认值。然后运行时调用构造函数。新的操作符将这两个独立的操作封装成一个看似单一的操作。如果不使用构造函数就无法创建实例,那么反序列化就永远不会在 .NET 中工作。也就是说,所谓的 ConstructorInfo 类型在调用其 Invoke(...
回答by Hallgrim
I noticed the "deadness" of the subject but just for clarification on further readers and to put a final answer that maybe wasn't possible when the question was posted. Here it goes.
我注意到这个主题的“死”,但只是为了向更多读者澄清并提出最终答案,这在问题发布时可能是不可能的。就到这里了。
It seems that you can instantiate a class without using it's constructors by assigning values to its properties. Here is the address where is the how-to in MSDN for this type of instantiation http://msdn.microsoft.com/en-us/library/bb397680.aspx.
似乎您可以通过为其属性分配值来实例化一个类,而无需使用它的构造函数。这是 MSDN 中此类实例化的操作方法http://msdn.microsoft.com/en-us/library/bb397680.aspx 的地址。
It seems like this is a technique that's not well known because I encountered it in a article in CodeProject and then googled it and didn't find anything about it and later on visited the MSDN Homepage and there was a post that linked me to that exact subject. So it seems that it's an unknown subject rather than a new one because the date on the CodeProject post dates May 2008.
似乎这是一种不太为人所知的技术,因为我在 CodeProject 的一篇文章中遇到了它,然后用谷歌搜索它并没有找到任何关于它的信息,后来访问了 MSDN 主页,有一个帖子将我链接到那个确切的主题。因此,它似乎是一个未知主题,而不是一个新主题,因为 CodeProject 帖子上的日期是 2008 年 5 月。
Hope this helps someone else that google's this and comes across with this question.
希望这可以帮助谷歌的其他人并遇到这个问题。