.net 对象构造函数可以返回空值吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/438325/
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
Can object constructor return a null?
提问by icelava
We have taken over some .NET 1.1 Windows Service code that spawns threads to read messages off a queue (SeeBeyond eGate JMS queue, but that is not important) and in turn spawns threads to process the message in the target application service. We are continually encountering logic and design decisions that is puzzling us to no end. Here is one example, where the message (lsMessage) has been retrieved from the queue and ready for processing
我们已经接管了一些 .NET 1.1 Windows 服务代码,这些代码生成线程以从队列(SeeBeyond eGate JMS 队列,但这并不重要)读取消息,然后生成线程来处理目标应用程序服务中的消息。我们不断遇到让我们无休止地困惑的逻辑和设计决策。这是一个示例,其中已从队列中检索消息 (lsMessage) 并准备好进行处理
if(lsMessage != null)
{
// Initialize a new thread class instance, pass in message
WorkerThread worker = new WorkerThread(lsMessage);
Process:
// Start a new thread to process the message
Thread targetWorker = new Thread(new ThreadStart(worker.ProcessMessage));
if(targetWorker != null)
{
targetWorker.Priority = ThreadPriority.Highest;
targetWorker.Name = "Worker " + queueKey.ToString();
targetWorker.Start();
// wait for worker thread to join back in specified period
bool isFinished = targetWorker.Join(SYNC_THREAD_TIMEOUT);
string message = worker.replyMsg;
if ( !isFinished ) // BF is timeout
{
targetWorker.Abort();
// [obscure developer name] 25/10/2004: calling Join() to wait for thread to terminate.
// for EAI listener threads problem, ensure no new thread is started
// before the old one ends
targetWorker.Join();
// prepare reply message
string errorMsg = string.Format("EAIMsg {0}: BF is timeout. Send sync message back to caller.", worker.messageKey);
log.Debug(errorMsg);
message = worker.GenErrorCode(message, errorMsg);
}
// Commit message
MQ.ReceiverCommit(queueKey, worker.messageKey, false);
// Send back the response to the caller
MQ.RespondSend(queueKey, message);
}
else
{
log.Debug(string.Format("Fail to start worker thread to process sync message. Thread returned is null. Sleep for {0} milliseconds.", LIMIT_RESOURCE_SLEEP));
Thread.Sleep(LIMIT_RESOURCE_SLEEP);
goto Process;
}
}
Please ignore the use of label and gotofor the moment; that is not the question. Our bewilderment is the check whether the Thread object is null right after instantiation. The else statement below seems to suggest the previous developers have encountered situations like this before. Of course, the original developers are long gone. So we would like to know, can the CLR really instantiate an object after the call to the constructor and return a null? We have no knowledge of such a possibility.
请暂时忽略label 和 goto的使用;这不是问题。我们的困惑是在实例化后立即检查 Thread 对象是否为空。下面的 else 语句似乎表明以前的开发人员以前遇到过这样的情况。当然,原来的开发者早已不在了。那么我们想知道,CLR真的可以在调用构造函数后实例化一个对象并返回null吗?我们不知道这种可能性。
回答by Gorpik
In my opinion, what the elsestatement suggests is that the previous developers didn't know their C#. A constructor always returns a constructed object or throws an exception.
在我看来,else声明暗示的是以前的开发人员不知道他们的 C#。构造函数总是返回一个构造的对象或抛出异常。
In the very old times, C++ constructors could return null, so maybe the problem comes from that. This is no longer true in C++ either, at least for the default newoperator.
在过去,C++ 构造函数可以 return null,所以问题可能来自于此。这在 C++ 中也不再适用,至少对于默认new运算符。
回答by Marc Gravell
Edit: for clarification there is an insane edge casewhere you can get nullfrom a class constructor, but frankly I don't think any real code should everexpect to deal with this level of crazy: What's the strangest corner case you've seen in C# or .NET?. To all normalintents : it won't happen.
编辑:澄清有一个疯狂的边缘的情况下,你可以得到null从类的构造函数,但坦率地说,我不认为任何真正的代码应该永远指望对付这种级别的疯狂:什么是你见过的最奇怪的角落情况C# 还是.NET?. 对于所有正常意图:它不会发生。
No, you can't get null from a classconstructor (Threadis a class). The only case I know of where a constructor can (seem to) return nullis Nullable<T>- i.e.
不,您不能从类构造函数(Thread是一个类)中获取 null 。我知道构造函数在哪里可以(似乎)返回的唯一情况null是Nullable<T>- 即
object foo = new int?(); // this is null
This is a slightly bigger problem with generics:
这是泛型的一个稍大的问题:
static void Oops<T>() where T : new() {
T t = new T();
if (t == null) throw new InvalidOperationException();
}
static void Main() {
Oops<int?>();
}
(of course, there are ways of checking/handling that scenario, such as : class)
(当然,有一些方法可以检查/处理该场景,例如: class)
Other than that, a constructor will always either return an object (or initialize a struct), or throw an exception.
除此之外,构造函数总是要么返回一个对象(或初始化一个结构体),要么抛出一个异常。
回答by Sesh
NO! that null check is redundant. Lot of C++ devs who moved to C# have this habit of a null check and I guess it is the same here.
不!空检查是多余的。许多转向 C# 的 C++ 开发人员都有这种空检查的习惯,我想这里也是一样。
The only thing is you should check the documentation to see if the constructor can throw any exception. In your case refer to http://msdn.microsoft.com/en-us/library/xx3ezzs2.aspxand as mentioned the constructor will always return a valid obj.
唯一的事情是您应该检查文档以查看构造函数是否可以抛出任何异常。在您的情况下,请参阅http://msdn.microsoft.com/en-us/library/xx3ezzs2.aspx并且如上所述构造函数将始终返回有效的 obj。
回答by core
You can make it appear like an object ctor returns null:
你可以让它看起来像一个返回 null 的对象构造函数:
http://seattlesoftware.wordpress.com/2008/03/05/returning-null-from-a-class-constructor/
http://seattlesoftware.wordpress.com/2008/03/05/returning-null-from-a-class-constructor/
Search for "Another pattern which I haven't seen used allows an invalid object to emulate a null reference" and read from there.
搜索“我没有见过的另一种模式允许无效对象模拟空引用”并从那里读取。
回答by Stevens Miller
As corementions, operator overloading can make it appear that a constructor returned null, when that's not what really happened. The authors of the article corefound say they haven't seen it used, but it actually is used in a very popular product: Unity.
如前所述core,运算符重载可以使构造函数看起来返回null,而实际上并非如此。core发现的文章作者说他们没有看到它被使用,但它实际上被用于一个非常受欢迎的产品:Unity。
This will compile and log a message at run time:
这将在运行时编译并记录一条消息:
using UnityEngine;
public class Test:MonoBehaviour
{
void Start()
{
AudioSource as = new AudioSource();
if (as == null)
{
Debug.Log("Looks null to me.");
}
}
}
Now, the fault here is mine, because one should notcall the AudioSourceconstructor directly. But one shouldknow that the ==operator is overloaded at the root of the inheritance tree for the objects Unity can reference. Here's what the Unity manual says about UnityEngine.Object's ==operator:
现在,这里的错误是我的,因为不应该AudioSource直接调用构造函数。但是应该知道,==运算符在 Unity 可以引用的对象的继承树的根部被重载。以下是 Unity 手册中关于UnityEngine.Object's==运算符的说明:
Be careful when comparing with null.
e.g.
GameObject go = new GameObject(); Debug.Log (go == null); // false Object obj = new Object(); Debug.Log (obj == null); // trueInstatiating a GameObject adds it to the scene so it's completely initialized (!destroyed). Instantiating a simple UnityEngine.Object has no such semantics, so the(sic) it stays in the 'destroyed' state which compares true to null.
与 null 比较时要小心。
例如
GameObject go = new GameObject(); Debug.Log (go == null); // false Object obj = new Object(); Debug.Log (obj == null); // true实例化一个 GameObject 会将它添加到场景中,因此它被完全初始化(!销毁)。实例化一个简单的 UnityEngine.Object 没有这样的语义,因此(原文如此)它保持在“销毁”状态,该状态将 true 与 null 进行比较。
While instantiating a GameObjectinitializes it, instantiating an AudioSourceobject doesn't, so the comparison with nullreturns true.
虽然实例化 a 会GameObject初始化它,但实例化一个AudioSource对象不会,因此与nullreturn的比较true。
This unusual idiom is made even more stealthy by virtue of the fact that attempts to reference properties of the uninitialized AudioSourceobject will throw null-reference exceptions, which I initially misinterpreted as meaning the object reference was null, not the property.
由于尝试引用未初始化AudioSource对象的属性将引发空引用异常,我最初将其误解为表示对象引用是null,而不是属性,因此这种不寻常的习惯用法变得更加隐蔽。
Others have answered the OP's question, but I wanted to add this answer because the OP's code might actually make sense if the Threadclass therein isn't the one we would expect it to be, just as Object(and its descendants) isn't quite what you might expect it to be in a Unity script (that is, it is actually UnityEngine.Object, rather than System.Object, which gets you the overloaded ==operator that so confused me).
其他人已经回答了 OP 的问题,但我想添加这个答案,因为如果Thread其中的类不是我们期望的类,那么 OP 的代码实际上可能有意义,就像Object(及其后代)不太一样您可能希望它在 Unity 脚本中(也就是说,它实际上是UnityEngine.Object,而不是System.Object,这使您成为==让我感到困惑的重载运算符)。

