#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 работает, когда у меня будет больше времени. Большое спасибо за вашу помощь!