Может ли конструктор объекта вернуть ноль? - PullRequest
33 голосов
/ 13 января 2009

Мы взяли на себя некоторый код службы Windows .NET 1.1, который порождает потоки для чтения сообщений из очереди (см. Очередь JMS SeeBeyond eGate, но это не важно) и, в свою очередь, порождает потоки для обработки сообщения в целевой службе приложения. Мы постоянно сталкиваемся с логикой и конструктивными решениями, которые озадачивают нас до бесконечности. Вот один пример, где сообщение (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;
    }
}

Пожалуйста, на данный момент игнорируйте использование метки и переходите к ; дело не в этом. Наше недоумение вызывает проверка, является ли объект Thread нулевым сразу после создания экземпляра . Представленное ниже утверждение else предполагает, что предыдущие разработчики сталкивались с подобными ситуациями раньше. Конечно, оригинальных разработчиков давно уже нет. Итак, мы хотели бы знать, может ли CLR создавать экземпляр объекта после вызова конструктора и возвращать нуль? Мы не знаем о такой возможности.

Ответы [ 5 ]

36 голосов
/ 13 января 2009

По моему мнению, утверждение else говорит о том, что предыдущие разработчики не знали своего C #. Конструктор всегда возвращает построенный объект или выдает исключение.

В очень давние времена конструкторы C ++ могли возвращать null, поэтому, возможно, проблема в этом. Это больше не верно в C ++, по крайней мере для оператора new по умолчанию.

26 голосов
/ 13 января 2009

Редактировать: для пояснения есть безумный край , где вы можете получить null из конструктора класса, но, честно говоря, я не думаю, что какой-либо реальный код должен когда-либо ожидать чтобы справиться с этим уровнем сумасшествия: Какой самый странный угловой случай вы видели в C # или .NET? . Ко всем нормальным намерениям: этого не произойдет.


Нет, вы не можете получить значение null из конструктора class (Thread - это класс). Единственный известный мне случай, когда конструктор может (кажется) вернуть null, это Nullable<T> - т.е.

object foo = new int?(); // this is null

Это немного большая проблема с генериками:

static void Oops<T>() where T : new() {
    T t = new T();
    if (t == null) throw new InvalidOperationException();
}

static void Main() {
    Oops<int?>();
}

(конечно, есть способы проверки / обработки этого сценария, такие как : class)

Кроме этого, конструктор всегда либо возвращает объект (или инициализирует структуру), либо выдает исключение.

2 голосов
/ 08 февраля 2018

Как упоминает core, перегрузка оператора может создать впечатление, что конструктор вернул null, когда это не то, что произошло на самом деле. Авторы статьи core нашли, что они не видели, что он использовал, но на самом деле он используется в очень популярном продукте: Unity.

Это скомпилирует и зарегистрирует сообщение во время выполнения:

using UnityEngine;

public class Test:MonoBehaviour
{
    void Start()
    {
        AudioSource as = new AudioSource();

        if (as == null)
        {
            Debug.Log("Looks null to me.");
        }
    }
}

Теперь ошибка здесь моя, потому что нужно не напрямую вызывать конструктор AudioSource. Но один должен знать, что оператор == перегружен в корне дерева наследования для объектов, на которые может ссылаться Unity. Вот что говорится в руководстве Unity об операторе UnityEngine.Object ==:

Будьте осторожны при сравнении с нулем.

, например

GameObject go = new GameObject();
Debug.Log (go == null); // false

Object obj = new Object();
Debug.Log (obj == null); // true

Установка GameObject добавляет его на сцену, так что он полностью инициализирован (! уничтожен). Создание простого UnityEngine.Object не имеет такой семантики, поэтому ( sic ) он остается в «разрушенном» состоянии, которое сравнивает значение true с нулем.

Хотя экземпляр GameObject инициализирует его, экземпляр объекта AudioSource - нет, поэтому сравнение с null возвращает true.

Эта необычная идиома сделана еще более скрытной благодаря тому факту, что попытки ссылаться на свойства неинициализированного объекта AudioSource будут вызывать исключения с нулевой ссылкой, которые я изначально неверно истолковал как означающие, что ссылка на объект была null, а не собственность.

Другие ответили на вопрос ОП, но я хотел бы добавить этот ответ, потому что код ОП может действительно иметь смысл, если класс Thread в нем не тот, который мы ожидаем, как Object ( и его потомки) не совсем то, что вы можете ожидать от сценария Unity (то есть на самом деле это UnityEngine.Object, а не System.Object, что приводит вас к перегруженному оператору ==, который так смутил меня) .

2 голосов
/ 17 марта 2009

Вы можете сделать его похожим на объект, который ctor возвращает null:

http://seattlesoftware.wordpress.com/2008/03/05/returning-null-from-a-class-constructor/

Поиск "Другой шаблон, который я не видел, позволяет недопустимому объекту эмулировать нулевую ссылку" и читает оттуда.

2 голосов
/ 13 января 2009

НЕТ! эта нулевая проверка избыточна. Многие разработчики C ++, которые перешли на C #, имеют эту привычку нулевой проверки, и я думаю, что здесь то же самое.

Единственное, что вы должны проверить документацию, чтобы увидеть, может ли конструктор вызвать какое-либо исключение. В вашем случае обратитесь к http://msdn.microsoft.com/en-us/library/xx3ezzs2.aspx и, как уже упоминалось, конструктор всегда будет возвращать действительный объект obj.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...