C ++ / CLI运行时错误:“对象引用未设置为对象的实例”

时间:2018-02-10 20:09:56

标签: c++-cli

第一:我已经读过几十个,如果没有接近SO(和其他网站)上的一百个其他线程关于“对象引用未设置为对象的实例”,(我得到的印象显然是一个常见的错误)但我似乎并没有“得到”它。所以,对不起,如果这是一个简单的错误或愚蠢的问题,但我是C ++ / CLI的新手,我已经坚持了很长一段时间了,我完全被难倒了。这个问题的特定版本可能已经在其他地方得到了解答,但是我找不到它,或者我确实发现它并且不太了解了解实际需要修复什么或如何修复它。 =(

我收到运行时错误(崩溃):

"Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at CreateEmployees(Int16 retCode, Void* hStmt, List`1 employee, Int32 numRows) in c:\directory\filename.cpp:line 385
   at main() in c:\directory\filename.cpp:line 472
   at _mainCRTStartup()
Press any key to continue . . ."

这是第472行:

List<Employee^>^ employee; // Line 471
CreateEmployees(retCode, hStmt, employee, numRows); // Line 472

以下是第385行的块:

void CreateEmployees(SQLRETURN retCode, SQLHANDLE hStmt, List<Employee^>^ employee, SQLLEN numRows)
{
    for (int i = 0; i < numRows; i++)
    {
        Employee^ temp = CreateNewEmployee(retCode, hStmt); // Line 384
        employee->Add(temp); // Line 385
        Console::WriteLine("Successfully created Employee {0}, Employee ID: {1}", i, employee[i]->getEmployeeId());
        retCode = SQLFetch(hStmt);
    }
}

以下是第384行上的代码:

Employee^ CreateNewEmployee(SQLRETURN retCode, SQLHANDLE hStmt)
{
int EmployeeId;
int DeptId;
String^ FirstName;
String^ LastName;
String^ Street;
String^ Phone;

System::String^ bufN;
char buf[256];
SQLINTEGER numBytes;

for (int i = 1; i <= 6; i++)
{
    retCode = SQLGetData(
        hStmt,
        i,           // COLUMN NUMBER of the data to get
        SQL_C_CHAR,  // DATA TYPE that you expect to receive
        buf,         // BUFFER to put the data that you expect to receive
        255,         // BUFFER size in bytes (-1 for null terminator)
        &numBytes    // SIZE in bytes of data returned
    );

    if (CHECK(retCode, "SqlGetData", false))
    {
        // Print the data we got.
        bufN = gcnew String((char *)buf);
        if (i == 1)
        {
            std::string s = msclr::interop::marshal_as<std::string>(bufN);
            EmployeeId = std::stoi(s, nullptr, 0);
        }
        else if (i == 2)
        {
            FirstName = bufN;
        }
        else if (i == 3)
        {
            LastName = bufN;
        }
        else if (i == 4)
        {
            Street = bufN;
        }
        else if (i == 5)
        {
            Phone = bufN;
        }
        else if (i == 6)
        {
            std::string s = msclr::interop::marshal_as<std::string>(bufN);
            DeptId = std::stoi(s, nullptr, 0);
        }
    }
}
Employee^ temp(gcnew Employee(EmployeeId, DeptId, FirstName, LastName, Street, Phone));
return temp;
}

1 个答案:

答案 0 :(得分:1)

标准警告:虽然可以用C ++ / CLI编写应用程序的主体,甚至可以使用WinForms在C ++ / CLI中编写GUI,但不建议这样做。 C ++ / CLI适用于互操作场景:C#或其他.Net代码需要与非托管C ++接口,C ++ / CLI可以提供两者之间的转换。因此,C ++ / CLI具有C ++的所有复杂性,C#的所有复杂性以及它自身的一些复杂性。对于主要开发,如果您需要托管代码,建议将C#与WinForms或WPF一起使用,如果您想要非托管,则建议使用带有MFC的C ++。

现在,那说:

List<Employee^>^ employee;

此时,employee为空,因为您尚未分配任何内容。 (顺便说一句,如果它是一个列表,变量名称可能应该是复数:“employees”。)

CreateEmployees(retCode, hStmt, employee, numRows);

好的,您将空引用传递给CreateEmployees方法。完全合法。

void CreateEmployees(SQLRETURN retCode, SQLHANDLE hStmt, List<Employee^>^ employee, SQLLEN numRows)
{
    employee->Add(temp);
}

employee仍然为空。在向其添加内容之前,您需要初始化列表。

这里有两种可能的修复方法。

修复1:在调用方法之前初始化。

List<Employee^>^ employees = gcnew List<Employee^>();

修复2:传入列表以接收方法的结果并不是在管理土地上做事的标准方法。切换方法的返回值以返回新列表。

List<Employee^>^ CreateEmployees(SQLRETURN retCode, SQLHANDLE hStmt, SQLLEN numRows)
{
    List<Employee^>^ result = gcnew List<Employee^>();

    for (int i = 0; i < numRows; i++)
    {
        ...
        result->Add(temp);
    }

    return result;
}