.net - tipos - ¿Puede el constructor de objetos devolver un nulo?
que es una instancia en java (5)
Hemos asumido algunos .NET 1.1 del código de servicio de Windows que genera hilos para leer mensajes de una cola (ver más allá de la cola eGate JMS, pero eso no es importante) y a su vez engendra hilos para procesar el mensaje en el servicio de aplicación de destino. Continuamente nos encontramos con decisiones de lógica y diseño que nos desconciertan sin fin. Aquí hay un ejemplo, donde el mensaje (lsMessage) ha sido recuperado de la cola y listo para ser procesado
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;
}
}
Por favor, ignore el uso de la etiqueta y goto por el momento; Esa no es la pregunta. Nuestro desconcierto es comprobar si el objeto Thread es nulo justo después de la instanciación . La declaración else a continuación parece sugerir que los desarrolladores anteriores han encontrado situaciones como esta antes. Por supuesto, los desarrolladores originales desaparecieron hace mucho tiempo. Entonces, nos gustaría saber si el CLR puede crear una instancia de un objeto después de la llamada al constructor y devolver un valor nulo. No tenemos conocimiento de tal posibilidad.
En mi opinión, lo else
sugiere la afirmación else
es que los desarrolladores anteriores no conocían su C #. Un constructor siempre devuelve un objeto construido o lanza una excepción.
En los viejos tiempos, los constructores de C ++ podían devolver null
, así que tal vez el problema provenga de eso. Esto ya no es cierto en C ++, al menos para el new
operador predeterminado.
¡NO! esa verificación nula es redundante. Muchos desarrolladores de C ++ que se mudaron a C # tienen este hábito de un cheque nulo y supongo que aquí es lo mismo.
Lo único que debe hacer es verificar la documentación para ver si el constructor puede lanzar una excepción. En su caso, consulte http://msdn.microsoft.com/en-us/library/xx3ezzs2.aspx y, como se mencionó, el constructor siempre devolverá un obj válido.
Puede hacer que parezca que un objeto ctor devuelve nulo:
http://seattlesoftware.wordpress.com/2008/03/05/returning-null-from-a-class-constructor/
Busque "Otro patrón que no he visto usado permite que un objeto no válido emule una referencia nula" y lea desde allí.
Editar: para aclarar hay un caso de borde loco donde puedes obtener un null
de un constructor de clase, pero francamente, no creo que ningún código real pueda esperar enfrentar este nivel de locura: ¿Cuál es el caso más extraño que has visto? en C # o .NET? . A todos los intentos normales : no sucederá.
No, no puede obtener un valor nulo de un constructor de clase (el Thread
es una clase). El único caso que sé de donde un constructor puede (parece) devolver null
es Nullable<T>
- es decir
object foo = new int?(); // this is null
Este es un problema un poco más grande con los genéricos:
static void Oops<T>() where T : new() {
T t = new T();
if (t == null) throw new InvalidOperationException();
}
static void Main() {
Oops<int?>();
}
(Por supuesto, hay formas de verificar / manejar ese escenario, como : class
)
Aparte de eso, un constructor siempre devolverá un objeto (o inicializará una estructura) o lanzará una excepción.
Como menciona el core
, la sobrecarga del operador puede hacer que parezca que un constructor devuelve null
, cuando eso no es lo que realmente sucedió. Los autores del core
del artículo encontrados dicen que no lo han visto usar, pero en realidad se usa en un producto muy popular: la Unidad.
Esto compilará y registrará un mensaje en tiempo de ejecución:
using UnityEngine;
public class Test:MonoBehaviour
{
void Start()
{
AudioSource as = new AudioSource();
if (as == null)
{
Debug.Log("Looks null to me.");
}
}
}
Ahora, la falla aquí es mía, porque uno no debe llamar al constructor de AudioSource
directamente. Pero uno debe saber que el operador ==
está sobrecargado en la raíz del árbol de herencia para los objetos a los que Unity puede hacer referencia. UnityEngine.Object
es lo que el manual de Unity dice sobre el operador ==
UnityEngine.Object
:
Tenga cuidado al comparar con nulo.
p.ej
GameObject go = new GameObject(); Debug.Log (go == null); // false Object obj = new Object(); Debug.Log (obj == null); // true
La instalación de un GameObject lo agrega a la escena para que esté completamente inicializado (! Destruido). La instancia de un UnityEngine.Object simple no tiene tal semántica, por lo que ( sic ) permanece en el estado ''destruido'' que compara verdadero con nulo.
Al instanciar un GameObject
inicializa, crear instancias de un objeto AudioSource
no lo hace, por lo que la comparación con null
devuelve true
.
Este idioma inusual se vuelve aún más sigiloso en virtud del hecho de que los intentos de referencia de propiedades del objeto AudioSource
no inicializado arrojarán excepciones de referencia nula, que inicialmente malinterpreté como que la referencia del objeto era null
, no la propiedad.
Otros han respondido la pregunta del OP, pero quería agregar esta respuesta porque el código OP podría tener sentido si la clase Thread
allí no es la que esperaríamos que fuera, así como Object
(y sus descendientes) no lo son. todo lo que se podría esperar que fuera en un guión de Unity (es decir, en realidad es UnityEngine.Object
, en lugar de System.Object
, lo que te da el operador sobrecargado ==
que tanto me confundió).