Исключение NullReferenceException при тестировании (m == nullptr) с типом матрицы Mathnet

#c# #matrix #c -cli #nullreferenceexception #math.net

#c# #матрица #c -cli #исключение nullreferenceexception #math.net

Вопрос:

Я борюсь со странным исключением NullReferenceException, которое возникает, когда я пытаюсь сравнить атрибут типа, производного от матричного типа из библиотеки MathNet, с nullptr.

Я хочу написать библиотеку классов C / CLI с преобразованием класса, полученным из MathNet ::Numerics::LinearAlgebra::Matrix, которая должна представлять позиции в трехмерном пространстве в виде матрицы 4×4 в однородных координатах. Поскольку я хочу иметь возможность устанавливать позиции относительно других позиций, у меня есть атрибут Transformation^ parent . if(parent == nullptr){ ... } Я хочу проверить, имеет ли текущее преобразование родительский элемент, но я получаю это исключение в строке с if(parent == nullptr) :

 An unhandled exception of type 'System.NullReferenceException' occurred in MathNet.Iridium.dll 
Additional information: Object reference not set to an instance of an object.
  

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

 /// Transformation.h
using namespace MathNet::Numerics::LinearAlgebra;
using namespace System;
ref class Transformation : Matrix
//ref class Transformation : A
{
public:
    Transformation(void);
    Transformation^ parent;
    void DoSomething();
};


/// Transformation.cpp
#include "StdAfx.h"
#include "Transformation.h"
Transformation::Transformation(void) : Matrix(4,4)
{
}
void Transformation::DoSomething()
{
    if(parent == nullptr)   // Produces NullReferenceException
    {
        Console::WriteLine("parent is nullptr");
    }
    Matrix^ m;
    if(m == nullptr)        // Produces NullReferenceException, too
    {
        Console::WriteLine("m is nullptr");
    }
}
  

Сравнение любой переменной матричного типа, которая на самом деле равна null, с nullptr, похоже, вызывает это исключение. Если он инициализирован правильно, исключения нет, так что это работает нормально:

 Matrix^ m = gcnew Matrix(4,4);
if(m == nullptr)        // works fine
{
    Console::WriteLine("");
}
  

При производном преобразовании из другого класса ref class Transformation : A вместо ref class Transformation : Matrix , все тоже работает нормально.

И теперь это становится действительно странным. Я хотел использовать свою библиотеку классов в C #-приложении. Вызов t.DoSomething() преобразования t вызывает исключение NullReferenceException . НО, если я включу нулевой тест непосредственно в свое приложение на C #, это сработает:

 Transformation t = new Transformation();
// t.DoSomething();      // Throws NullReferenceException
if (t.parent == null)    // OK!
{
    Console.WriteLine("parent is null");
}
  

Выполнение того же самого в приложении C / ClI снова вызывает исключение NullReferenceException:

 Transformation^ t = gcnew Transformation();
// t->DoSomething();     // Throws NullReferenceException
if(t->parent == nullptr) // Throws NullReferenceException
{
    Console::WriteLine("parent is nullptr");
}
  

Любые предложения, откуда это может исходить? Я действительно очень озадачен…

Я использую MathNet.Библиотека Idirium, версия 2008.8.16.470

Комментарии:

1. Обычно это указывает на то, что это значение равно нулю. Однако не соответствует вашему тестовому коду. Возможно, проблема с управлением версиями.

2. Если бы это (значение t в данном контексте) было null, я не смог бы вызвать doSomething() для t или я ошибаюсь? Исключение выдается только внутри doSomething(), а не при его вызове.

3. Это отличается для C / CLI, он не генерирует код, чтобы гарантировать, что это не null, как это делает C #. Он бомбит позже, когда вы пытаетесь получить доступ к члену класса. Может быть трудно диагностировать. Но я согласен, что ваши тесты делают маловероятным, что это реальная причина проблемы. Посмотрите на это в отладчике для любого вида подсказки.

4. Я могу проверить «это» в отладчике (не указывает на «<неопределенное значение>»), а также правильно инициализирован его вложенный атрибут типа Matrix. Только родительский элемент указывает на «<неопределенное значение>». Поскольку проблема также возникает с локальными переменными (см. Определение класса выше, Matrix ^ m) Я думаю, это не может быть проблемой с «этим»?

Ответ №1:

В C # возможно, по крайней мере, чтобы оператор == был реализован таким образом, чтобы генерировать нулевую ссылку.

Можете ли вы попробовать вызвать Object::ReferenceEquals(obj, null) и посмотреть, работает это или нет?

Комментарии:

1. Спасибо, Энди, за сравнение с if(Object::ReferenceEquals(parent, nullptr)) проходами без исключения! Так это тонкость в реализации Matrix?

2. @richn : Если под «тонкостью» вы подразумеваете «ошибку», то да.

3. @ildjarn Ха-ха 😉 Я просто хотел знать, могу ли я «видеть», когда использовать ReferenceEquals() и когда == .

4. @richn: Единственный способ «увидеть» — это посмотреть исходный код Matrix и посмотреть на реализацию operator== . Так что, если у вас его нет и вы не можете его декомпилировать, возможно, вам не повезло. Это, безусловно, ошибка в этом коде, хотя, как равные, реализации GetHashCode и operator НИКОГДА не должны вызывать исключения, согласно документации MSDN.

5. @Andy MathNet является открытым исходным кодом, и после быстрого ознакомления с реализацией Matrix я не смог найти никакой реализации оператора == . Но ничего, я пока пойду с вашим исправлением и поищу причину == , по которой doens’t работает, когда у меня будет больше времени. Большое спасибо за вашу помощь!