I have some code and when it executes, it throws a NullReferenceException
, saying:
我有一些代码,当它执行时,它抛出一个NullReferenceException,说:
Object reference not set to an instance of an object.
对象引用没有设置为对象的实例。
What does this mean, and what can I do to fix this error?
这意味着什么,我能做些什么来弥补这个错误呢?
33 个解决方案
#1
1992
What is the cause?
Bottom Line
You are trying to use something that is null
(or Nothing
in VB.NET). This means you either set it to null
, or you never set it to anything at all.
您尝试使用的是null(或VB.NET中没有的)。这意味着您要么将其设置为null,要么您从未将其设置为任何值。
Like anything else, null
gets passed around. If it is null
in method "A", it could be that method "B" passed a null
to method "A".
像其他任何东西一样,null被传递。如果方法“A”中为null,则可能是方法“B”传递了null到方法“A”。
The rest of this article goes into more detail and shows mistakes that many programmers often make which can lead to a NullReferenceException
.
本文的其余部分将更详细地介绍,并指出许多程序员经常犯的错误,这些错误可能导致NullReferenceException。
More Specifically
The runtime throwing a NullReferenceException
always means the same thing: you are trying to use a reference, and the reference is not initialized (or it was once initialized, but is no longer initialized).
运行时抛出一个NullReferenceException总是意味着相同的事情:您正在尝试使用引用,并且引用没有初始化(或者它曾经被初始化,但是不再被初始化)。
This means the reference is null
, and you cannot access members (such as methods) through a null
reference. The simplest case:
这意味着引用是空的,并且不能通过空引用访问成员(比如方法)。最简单的例子:
string foo = null;
foo.ToUpper();
This will throw a NullReferenceException
at the second line because you can't call the instance method ToUpper()
on a string
reference pointing to null
.
这将在第二行中抛出一个NullReferenceException,因为您不能在一个指向null的字符串引用上调用实例方法ToUpper()。
Debugging
How do you find the source of a NullReferenceException
? Apart from looking at the exception itself, which will be thrown exactly at the location where it occurs, the general rules of debugging in Visual Studio apply: place strategic breakpoints and inspect your variables, either by hovering the mouse over their names, opening a (Quick)Watch window or using the various debugging panels like Locals and Autos.
如何找到NullReferenceException的源?除了看异常本身,这将被完全在它出现的位置,在Visual Studio调试应用的一般规则:战略断点和检查你的变量,通过鼠标盘旋在他们的名字,打开(快速)监视窗口或使用各种调试面板像当地人和汽车。
If you want to find out where the reference is or isn't set, right-click its name and select "Find All References". You can then place a breakpoint at every found location and run your program with the debugger attached. Every time the debugger breaks on such a breakpoint, you need to determine whether you expect the reference to be non-null, inspect the variable and and verify that it points to an instance when you expect it to.
如果您想要查找引用的位置或未设置的位置,请右键单击它的名称并选择“查找所有引用”。然后,您可以在每个找到的位置上放置一个断点,并使用附加的调试器运行您的程序。每次调试器在这样一个断点上断开时,您需要确定是否希望引用非空,检查变量,并验证它指向一个实例。
By following the program flow this way, you can find the location where the instance should not be null, and why it isn't properly set.
通过这种方式跟踪程序流,您可以找到实例不应该为null的位置,以及为什么它没有正确设置。
Examples
Some common scenarios where the exception can be thrown:
可以抛出异常的一些常见场景:
Generic
ref1.ref2.ref3.member
If ref1 or ref2 or ref3 is null, then you'll get a NullReferenceException
. If you want to solve the problem, then find out which one is null by rewriting the expression to its simpler equivalent:
如果ref1或ref2或ref3是null,那么您将获得一个NullReferenceException。如果你想要解决这个问题,那么你可以通过把表达式改写成简单的等价形式来找出哪个是空的:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
Specifically, in HttpContext.Current.User.Identity.Name
, the HttpContext.Current
could be null, or the User
property could be null, or the Identity
property could be null.
具体来说,在HttpContext.Current.User.Identity。名字,HttpContext。当前可以是null,或者用户属性可以是null,或者标识属性可以为null。
Indirect
public class Person {
public int Age { get; set; }
}
public class Book {
public Person Author { get; set; }
}
public class Example {
public void Foo() {
Book b1 = new Book();
int authorAge = b1.Author.Age; // You never initialized the Author property.
// there is no Person to get an Age from.
}
}
If you want to avoid the child (Person) null reference, you could initialize it in the parent (Book) object's constructor.
如果您想避免子(Person)空引用,您可以在父(Book)对象的构造函数中初始化它。
Nested Object Initializers
The same applies to nested object initializers:
同样适用于嵌套对象初始化器:
Book b1 = new Book { Author = { Age = 45 } };
This translates to
这个翻译
Book b1 = new Book();
b1.Author.Age = 45;
While the new
keyword is used, it only creates a new instance of Book
, but not a new instance of Person
, so the Author
the property is still null
.
虽然使用了新的关键字,但它只创建了一个新的Book实例,而不是Person的新实例,因此该属性仍然为null。
Nested Collection Initializers
public class Person {
public ICollection<Book> Books { get; set; }
}
public class Book {
public string Title { get; set; }
}
The nested collection initializers behave the same:
嵌套集合初始化器的行为相同:
Person p1 = new Person {
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
This translates to
这个翻译
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
The new Person
only creates an instance of Person
, but the Books
collection is still null
. The collection initializer syntax does not create a collection for p1.Books
, it only translates to the p1.Books.Add(...)
statements.
新来的人只创建Person的实例,但是书籍的集合仍然是空的。集合初始化语法不为p1创建集合。书籍,它只会翻译成p1.Books.Add(…)语句。
Array
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
Array Elements
Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
// initialized. There is no Person to set the Age for.
Jagged Arrays
long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
// Use array[0] = new long[2]; first.
Collection/List/Dictionary
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
Range Variable (Indirect/Deferred)
public class Person {
public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
// on the line above. "p" is null because the
// first element we added to the list is null.
Events
public class Demo
{
public event EventHandler StateChanged;
protected virtual void OnStateChanged(EventArgs e)
{
StateChanged(this, e); // Exception is thrown here
// if no event handlers have been attached
// to StateChanged event
}
}
Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
如果您用不同于本地的命名字段,您可能会意识到您从未初始化字段。
public class Form1 {
private Customer customer;
private void Form1_Load(object sender, EventArgs e) {
Customer customer = new Customer();
customer.Name = "John";
}
private void Button_Click(object sender, EventArgs e) {
MessageBox.Show(customer.Name);
}
}
This can be solved by following the convention to prefix fields with an underscore:
这可以通过遵循惯例的前缀字段来解决:
private Customer _customer;
ASP.NET Page Life cycle:
public partial class Issues_Edit : System.Web.UI.Page
{
protected TestIssue myIssue;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Only called on first load, not when button clicked
myIssue = new TestIssue();
}
}
protected void SaveButton_Click(object sender, EventArgs e)
{
myIssue.Entry = "NullReferenceException here!";
}
}
ASP.NET Session Values
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
ASP.NET MVC empty view models
If the exception occurs when referencing a property of @Model
in an ASP.NET MVC view, you need to understand that the Model
gets set in your action method, when you return
a view. When you return an empty model (or model property) from your controller, the exception occurs when the views access it:
如果在ASP中引用@Model的属性时发生异常。NET MVC视图,您需要了解当您返回一个视图时,模型会在您的操作方法中被设置。当您从控制器返回空模型(或模型属性)时,当视图访问它时发生异常:
// Controller
public class Restaurant:Controller
{
public ActionResult Search()
{
return View(); // Forgot the provide a Model here.
}
}
// Razor view
@foreach (var restaurantSearch in Model.RestaurantSearch) // Throws.
{
}
<p>@Model.somePropertyName</p> <!-- Also throws -->
WPF Control Creation Order and Events
WPF controls are created during the call to InitializeComponent
in the order they appear in the visual tree. A NullReferenceException
will be raised in the case of early-created controls with event handlers, etc. , that fire during InitializeComponent
which reference late-created controls.
WPF控件是在调用InitializeComponent时创建的,它们是在可视树中出现的。在早期创建的控件和事件处理程序之间,将会出现一个NullReferenceException。
For example :
例如:
<Grid>
<!-- Combobox declared first -->
<ComboBox Name="comboBox1"
Margin="10"
SelectedIndex="0"
SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Content="Item 1" />
<ComboBoxItem Content="Item 2" />
<ComboBoxItem Content="Item 3" />
</ComboBox>
<!-- Label declared later -->
<Label Name="label1"
Content="Label"
Margin="10" />
</Grid>
Here comboBox1
is created before label1
. If comboBox1_SelectionChanged
attempts to reference `label1, it will not yet have been created.
在label1之前创建了comboBox1。如果comboBox1_SelectionChanged尝试引用“label1,它将不会被创建”。
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Changing the order of the declarations in the XAML (i.e., listing label1
before comboBox1
, ignoring issues of design philosophy, would at least resolve the NullReferenceException
here.
更改XAML中声明的顺序(即:在comboBox1之前列出label1,忽略了设计哲学的问题,至少可以解决这里的NullReferenceException。
Cast with as
var myThing = someObject as Thing;
This doesn't throw an InvalidCastException but returns a null
when the cast fails (and when someObject is itself null). So be aware of that.
这不会抛出InvalidCastException,但是当强制转换失败时返回一个null(当某个对象本身为空时)。所以要意识到这点。
LINQ FirstOrDefault() and SingleOrDefault()
The plain versions First()
and Single()
throw exceptions when there is nothing. The "OrDefault" versions return null in that case. So be aware of that.
普通版本第一个()和单个()抛出异常时,什么都没有。在这种情况下,“OrDefault”版本返回null。所以要意识到这点。
foreach
foreach
throws when you try to iterate null collection. Usually caused by unexpected null
result from methods that return collections.
在尝试迭代空集合时,foreach抛出。通常由返回集合的方法的意外空结果导致。
List<int> list = null;
foreach(var v in list) { } // exception
More realistic example - select nodes from XML document. Will throw if nodes are not found but initial debugging shows that all properties valid:
更现实的例子——从XML文档中选择节点。如果未找到节点,则会抛出,但初始调试显示所有属性都是有效的:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
Ways to Avoid
Explicitly check for null
and ignore null values.
If you expect the reference sometimes to be null, you can check for it being null
before accessing instance members:
如果您期望引用有时为null,那么您可以在访问实例成员之前检查它是否为null:
void PrintName(Person p) {
if (p != null) {
Console.WriteLine(p.Name);
}
}
Explicitly check for null
and provide a default value.
Methods call you expect to return an instance can return null
, for example when the object being sought cannot be found. You can choose to return a default value when this is the case:
方法调用您期望返回一个实例可以返回null,例如,当正在寻找的对象无法被找到时。当情况是这样时,您可以选择返回一个默认值:
string GetCategory(Book b) {
if (b == null)
return "Unknown";
return b.Category;
}
Explicitly check for null
from method calls and throw a custom exception.
You can also throw a custom exception, only to catch it in the calling code:
您还可以抛出一个定制的异常,只在调用代码中捕获它:
string GetCategory(string bookTitle) {
var book = library.FindBook(bookTitle); // This may return null
if (book == null)
throw new BookNotFoundException(bookTitle); // Your custom exception
return book.Category;
}
Use Debug.Assert
if a value should never be null
, to catch the problem earlier than the exception occurs.
When you know during development that a method maybe can, but never should return null
, you can use Debug.Assert()
to break as soon as possible when it does occur:
当您在开发过程中知道一个方法可能可以,但是永远不应该返回null时,您可以使用Debug.Assert()在发生时尽快中断:
string GetTitle(int knownBookID) {
// You know this should never return null.
var book = library.GetBook(knownBookID);
// Exception will occur on the next line instead of at the end of this method.
Debug.Assert(book != null, "Library didn't return a book for known book ID.");
// Some other code
return book.Title; // Will never throw NullReferenceException in Debug mode.
}
Though this check will not end up in your release build, causing it to throw the NullReferenceException
again when book == null
at runtime in release mode.
虽然此检查不会在您的发布版本中结束,但是在运行时,当book == null时,它会再次抛出NullReferenceException。
Use GetValueOrDefault()
for nullable value types to provide a default value when they are null
.
DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.
appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default
Use the null coalescing operator: ??
[C#] or If()
[VB].
The shorthand to providing a default value when a null
is encountered:
当遇到null时,提供默认值的简写如下:
IService CreateService(ILogger log, Int32? frobPowerLevel)
{
var serviceImpl = new MyService(log ?? NullLog.Instance);
// Note that the above "GetValueOrDefault()" can also be rewritten to use
// the coalesce operator:
serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}
Use the null condition operator: ?.
(available in C# 6 and VB.NET 14):
This is also sometimes called the safe navigation or Elvis (after its shape) operator. If the expression on the left side of the operator is null, then the right side will not be evaluated, and null is returned instead. That means cases like this:
这有时也被称为安全导航或猫王(在它的形状之后)。如果操作符左侧的表达式为null,那么右侧将不会被计算,反之则返回null。这意味着这样的情况:
var title = person.Title.ToUpper();
If the person does not have a title, this will throw an exception because it is trying to call ToUpper
on a property with a null value.
如果这个人没有标题,这将抛出一个异常,因为它试图在一个具有空值的属性上调用ToUpper。
In C# 5 and below, this can be guarded with:
在c# 5和下面,可以使用以下方法进行保护:
var title = person.Title == null ? null : person.Title.ToUpper();
Now the title variable will be null instead of throwing an exception. C# 6 introduces a shorter syntax for this:
现在title变量将为空,而不是抛出异常。c# 6引入了一个更简短的语法:
var title = person.Title?.ToUpper();
This will result in the title variable being null
, and the call to ToUpper
is not made if person.Title
is null
.
这将导致title变量为空,而对ToUpper的调用不是由person生成的。标题为空。
Of course, you still have to check title
for null or use the null condition operator together with the null coalescing operator (??
) to supply a default value:
当然,您仍然需要检查title是否为null,或者使用null条件操作符和null合并操作符(??)来提供默认值:
// regular null check
int titleLength = 0;
if (title != null)
titleLength = title.Length; // If title is null, this would throw NullReferenceException
// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;
#2
259
NullReference Exception — Visual Basic
The NullReference Exception
for Visual Basic is no different from the one in C#. After all, they are both reporting the same exception defined in the .NET Framework which they both use. Causes unique to Visual Basic are rare (perhaps only one).
Visual Basic的NullReference异常与c#中没有任何不同。毕竟,它们都报告了在. net框架中定义的相同的异常。独特的视觉基础是罕见的(也许只有一个)。
This answer will use Visual Basic terms, syntax, and context. The examples used come from a large number of past Stack Overflow questions. This is to maximize relevance by using the kinds of situations often seen in posts. A bit more explanation is also provided for those who might need it. An example similar to yours is very likely listed here.
这个答案将使用Visual Basic术语、语法和上下文。所使用的示例来自大量过去的堆栈溢出问题。这是通过在文章中经常看到的情况来最大化相关性。还为可能需要的人提供了更多的解释。类似于您的示例很可能在这里列出。
Note:
注意:
- This is concept-based: there is no code for you to paste into your project. It is intended to help you understand what causes a
NullReferenceException
(NRE), how to find it, how to fix it, and how to avoid it. An NRE can be caused many ways so this is unlikely to be your sole encounter. - 这是基于概念的:没有代码可以粘贴到您的项目中。它的目的是帮助您了解什么导致了NullReferenceException (NRE),如何找到它,如何修复它,以及如何避免它。一个NRE可以通过多种方式产生,所以这不太可能是你唯一的遭遇。
- The examples (from Stack Overflow posts) do not always show the best way to do something in the first place.
- 示例(从堆栈溢出的帖子)并不总是显示最好的方法来做一些事情。
- Typically, the simplest remedy is used.
- 通常,使用最简单的补救方法。
Basic Meaning
The message "Object not set to an instance of Object" means you are trying to use an object which has not been initialized. This boils down to one of these:
消息“对象未设置为对象实例”意味着您正在尝试使用尚未初始化的对象。这可以归结为一个问题:
- Your code declared an object variable, but it did not initialize it (create an instance or 'instantiate' it)
- 您的代码声明了一个对象变量,但是它没有初始化它(创建一个实例或者“实例化”它)
- Something which your code assumed would initialize an object, did not
- 你的代码假设会初始化一个对象,但没有。
- Possibly, other code prematurely invalidated an object still in use
- 可能,其他代码过早地使一个仍在使用的对象失效。
Finding The Cause
Since the problem is an object reference which is Nothing
, the answer is to examine them to find out which one. Then determine why it is not initialized. Hold the mouse over the various variables and Visual Studio (VS) will show their values - the culprit will be Nothing
.
由于这个问题是一个对象引用,它什么都不是,所以答案是检查它们以找出哪一个。然后确定它没有初始化的原因。把鼠标放在不同的变量上,Visual Studio (VS)将显示它们的值——罪魁祸首是什么都不是。
You should also remove any Try/Catch blocks from the relevant code, especially ones where there is nothing in the Catch block. This will cause your code to crash when it tries to use an object which is Nothing
. This is what you want because it will identify the exact location of the problem, and allow you to identify the object causing it.
您还应该从相关代码中删除任何Try/Catch块,特别是在Catch块中没有内容的地方。这将导致您的代码在试图使用一个没有任何内容的对象时崩溃。这是您想要的,因为它将识别问题的确切位置,并允许您识别导致它的对象。
A MsgBox
in the Catch which displays Error while...
will be of little help. This method also leads to very bad Stack Overflow questions, because you can't describe the actual exception, the object involved or even the line of code where it happens.
在Catch中显示错误的MsgBox。会有一点帮助。这种方法还会导致非常糟糕的堆栈溢出问题,因为您无法描述实际的异常、所涉及的对象,甚至无法描述它所发生的代码行。
You can also use the Locals Window
(Debug -> Windows -> Locals) to examine your objects.
您还可以使用local窗口(Debug ->窗口->本地)来检查对象。
Once you know what and where the problem is, it is usually fairly easy to fix and faster than posting a new question.
一旦你知道了问题所在,解决问题的方法往往比发布一个新问题要容易得多。
See also:
参见:
- Breakpoints
- 断点
- MSDN: How to: Use the Try/Catch Block to Catch Exceptions
- MSDN:如何:使用Try/Catch块捕获异常。
- MSDN: Best Practices for Exceptions
- MSDN:例外的最佳实践。
Examples and Remedies
Class Objects / Creating an Instance
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
The problem is that Dim
does not create a CashRegister object; it only declares a variable named reg
of that Type. Declaring an object variable and creating an instance are two different things.
问题是Dim不创建现金注册对象;它只声明一个名为reg的变量。声明一个对象变量并创建一个实例是两个不同的事情。
Remedy
补救措施
The New
operator can often be used to create the instance when you declare it:
当您声明该实例时,通常可以使用新的操作符来创建实例:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
When it is only appropriate to create the instance later:
当它只适合于稍后创建实例时:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Note: Do not use Dim
again in a procedure, including the constructor (Sub New
):
注意:在过程中不要再次使用Dim,包括构造函数(Sub - New):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
This will create a local variable, reg
, which exists only in that context (sub). The reg
variable with module level Scope
which you will use everywhere else remains Nothing
.
这将创建一个局部变量reg,它只存在于该上下文(sub)中。您将在其他地方使用的模块级范围的reg变量仍然没有。
Missing the
New
operator is the #1 cause ofNullReference Exceptions
seen in the Stack Overflow questions reviewed.缺少新操作符是在堆栈溢出问题中看到的NullReference异常的#1原因。
Visual Basic tries to make the process clear repeatedly using
New
: Using theNew
Operator creates a new object and callsSub New
-- the constructor -- where your object can perform any other initialization.Visual Basic试图用新方法使过程变得清晰:使用新操作符创建一个新对象,并调用subnew——构造函数——在这里,对象可以执行任何其他初始化。
To be clear, Dim
(or Private
) only declares a variable and its Type
. The Scope of the variable - whether it exists for the entire module/class or is local to a procedure - is determined by where it is declared. Private | Friend | Public
defines the access level, not Scope.
要清楚,Dim(或私有)只声明一个变量及其类型。变量的范围——是否存在于整个模块/类或者是本地的程序——取决于声明的位置。Private | Friend | Public定义访问级别,而不是范围。
For more information, see:
有关更多信息,请参见:
- New Operator
- 新的操作符
- Scope in Visual Basic
- 在Visual Basic范围
- Access Levels in Visual Basic
- 在Visual Basic中访问级别。
- Value Types and Reference Types
- 值类型和引用类型。
Arrays
Arrays must also be instantiated:
还必须实例化数组:
Private arr as String()
This array has only been declared, not created. There are several ways to initialize an array:
这个数组只被声明,而不是创建。有几种方法来初始化一个数组:
Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}
' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}
Note: Beginning with VS 2010, when initializing a local array using a literal and Option Infer
, the As <Type>
and New
elements are optional:
注意:从VS 2010开始,当使用文字和选项来初始化本地数组时,As
Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}
The data Type and array size are inferred from the data being assigned. Class/Module level declarations still require As <Type>
with Option Strict
:
数据类型和数组大小是根据分配的数据推断出来的。类/模块级声明仍然需要
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Example: Array of class objects
示例:类对象数组。
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
The array has been created, but the Foo
objects in it have not.
数组已经创建,但是Foo对象没有。
Remedy
补救措施
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Using a List(Of T)
will make it quite difficult to have an element without a valid object:
使用一个列表(T)将使一个没有有效对象的元素变得非常困难:
Dim FooList As New List(Of Foo) ' List created, but it is empty
Dim f As Foo ' Temporary variable for the loop
For i As Integer = 0 To 5
f = New Foo() ' Foo instance created
f.Bar = i * 10
FooList.Add(f) ' Foo object added to list
Next
For more information, see:
有关更多信息,请参见:
- Option Infer Statement
- 选项推断声明
- Scope in Visual Basic
- 在Visual Basic范围
- Arrays in Visual Basic
- Visual Basic中的数组
Lists and Collections
.NET collections (of which there are many varieties - Lists, Dictionary, etc.) must also be instantiated or created.
. net集合(其中有许多种类——列表、字典等)也必须被实例化或创建。
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
You get the same exception for the same reason - myList
was only declared, but no instance created. The remedy is the same:
同样的原因也会得到相同的异常——myList只声明,但没有创建实例。补救方法是一样的:
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
A common oversight is a class which uses a collection Type
:
常见的疏忽是使用集合类型的类:
Public Class Foo
Private barList As List(Of Bar)
Friend Function BarCount As Integer
Return barList.Count
End Function
Friend Sub AddItem(newBar As Bar)
If barList.Contains(newBar) = False Then
barList.Add(newBar)
End If
End Function
Either procedure will result in an NRE, because barList
is only declared, not instantiated. Creating an instance of Foo
will not also create an instance of the internal barList
. It may have been the intent to do this in the constructor:
任何一个过程都将导致一个NRE,因为barList只被声明,而不是实例化。创建一个Foo实例也不会创建内部barList的实例。它可能是在构造函数中这样做的目的:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
As before, this is incorrect:
如前所述,这是不正确的:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
For more information, see List(Of T)
Class.
有关更多信息,请参见列表(T)类。
Data Provider Objects
Working with databases presents many opportunities for a NullReference because there can be many objects (Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) in use at once. Note: It does not matter which data provider you are using -- MySQL, SQL Server, OleDB, etc. -- the concepts are the same.
使用数据库提供了许多机会NullReference因为可以有许多对象(命令、连接、事务、数据集,数据表,我们应该....)使用。注意:您使用的数据提供者(MySQL、SQL Server、OleDB等)并不重要,概念是相同的。
Example 1
示例1
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer
con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()
MaxRows = ds.Tables("foobar").Rows.Count ' Error
As before, the ds
Dataset object was declared, but an instance was never created. The DataAdapter
will fill an existing DataSet
, not create one. In this case, since ds
is a local variable, the IDE warns you that this might happen:
与前面一样,声明了ds数据集对象,但从未创建实例。DataAdapter将填充现有的数据集,而不是创建一个。在本例中,由于ds是一个局部变量,IDE警告您这可能会发生:
When declared as a module/class level variable, as appears to be the case with con
, the compiler can't know if the object was created by an upstream procedure. Do not ignore warnings.
当被声明为模块/类级别变量时,似乎是con的情况,编译器不知道该对象是由上游过程创建的。不要忽视警告。
Remedy
补救措施
Dim ds As New DataSet
Example 2
示例2
ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")
txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)
A typo is a problem here: Employees
vs Employee
. There was no DataTable
named "Employee" created, so a NullReferenceException
results trying to access it. Another potential problem is assuming there will be Items
which may not be so when the SQL includes a WHERE clause.
在这里输入错误是一个问题:雇员和雇员。没有创建名为“Employee”的DataTable,因此试图访问它的NullReferenceException结果。另一个潜在的问题是,假设在SQL中包含WHERE子句时可能不会出现某些项。
Remedy
补救措施
Since this uses one table, using Tables(0)
will avoid spelling errors. Examining Rows.Count
can also help:
由于使用了一个表,所以使用表(0)可以避免拼写错误。检查行。数也可以帮助:
If ds.Tables(0).Rows.Count > 0 Then
txtID.Text = ds.Tables(0).Rows(0).Item(1)
txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If
Fill
is a function returning the number of Rows
affected which can also be tested:
Fill是返回受影响的行数的函数,也可以进行测试:
If da.Fill(ds, "Employees") > 0 Then...
Example 3
示例3
Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)
If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then
The DataAdapter
will provide TableNames
as shown in the previous example, but it does not parse names from the SQL or database table. As a result, ds.Tables("TICKET_RESERVATION")
references a non-existent table.
DataAdapter将按照前面的示例提供TableNames,但它不解析SQL或数据库表中的名称。因此,表(“TICKET_RESERVATION”)引用了一个不存在的表。
The Remedy is the same, reference the table by index:
补救方法是相同的,参照表的索引:
If ds.Tables(0).Rows.Count > 0 Then
See also DataTable Class.
参见DataTable类。
Object Paths / Nested
If myFoo.Bar.Items IsNot Nothing Then
...
The code is only testing Items
while both myFoo
and Bar
may also be Nothing. The remedy is to test the entire chain or path of objects one at a time:
代码只是测试项目,而myFoo和Bar也可能什么都不是。补救方法是一次测试一个对象的整个链或路径:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
is important. Subsequent tests will not be performed once the first False
condition is encountered. This allows the code to safely 'drill' into the object(s) one 'level' at a time, evaluating myFoo.Bar
only after (and if) myFoo
is determined to be valid. Object chains or paths can get quite long when coding complex objects:
需要说明是非常重要的。在遇到第一个错误条件后,将不会执行后续测试。这使得代码可以一次安全地“钻”到对象的一个“级别”,评估myFoo。只有在(并且如果)myFoo被确定为有效之后,Bar才会生效。当编码复杂对象时,对象链或路径会变得很长:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
It is not possible to reference anything 'downstream' of a null
object. This also applies to controls:
不可能引用空对象的任何“下游”。这也适用于控制:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Here, myWebBrowser
or Document
could be Nothing or the formfld1
element may not exist.
在这里,myWebBrowser或Document可能不存在,或者formfld1元素可能不存在。
UI Controls
Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
& "FROM Invoice where invoice_no = '" & _
Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
Me.expiry.Text & "'", con)
Among other things, this code does not anticipate that the user may not have selected something in one or more UI controls. ListBox1.SelectedItem
may well be Nothing
, so ListBox1.SelectedItem.ToString
will result in an NRE.
除其他外,此代码没有预料到用户可能没有在一个或多个UI控件中选择某些内容。ListBox1。SelectedItem很可能什么都不是,所以ListBox1.SelectedItem。ToString将导致NRE。
Remedy
补救措施
Validate data before using it (also use Option Strict
and SQL parameters):
在使用前验证数据(也使用选项严格和SQL参数):
Dim expiry As DateTime ' for text date validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
(ListBox1.SelectedItems.Count > 0) AndAlso
(ComboBox2.SelectedItems.Count > 0) AndAlso
(DateTime.TryParse(expiry.Text, expiry) Then
'... do stuff
Else
MessageBox.Show(...error message...)
End If
Alternatively, you can use (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
或者,也可以使用(ComboBox5)。设置SelectedItem不是什么)以及……
Visual Basic Forms
Public Class Form1
Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
Controls("TextBox2"), Controls("TextBox3"), _
Controls("TextBox4"), Controls("TextBox5"), _
Controls("TextBox6")}
' same thing in a different format:
Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}
' Immediate NRE:
Private somevar As String = Me.Controls("TextBox1").Text
This is a fairly common way to get an NRE. In C#, depending on how it is coded, the IDE will report that Controls
does not exist in the current context, or "cannot reference non-static member". So, to some extent, this is a VB-only situation. It is also complex because it can result in a failure cascade.
这是获得NRE的一个相当普遍的方法。在c#中,根据它的编码方式,IDE将报告当前上下文中不存在控件,或者“不能引用非静态成员”。因此,在某种程度上,这是一个vb的情况。它也很复杂,因为它会导致失败级联。
The arrays and collections cannot be initialized this way. This initialization code will run before the constructor creates the Form
or the Controls
. As a result:
数组和集合不能以这种方式初始化。此初始化代码将在构造函数创建窗体或控件之前运行。结果:
- Lists and Collection will simply be empty
- 列表和集合将是空的。
- The Array will contain five elements of Nothing
- 该数组将包含5个元素。
- The
somevar
assignment will result in an immediate NRE because Nothing doesn't have a.Text
property - somevar赋值将导致立即的NRE,因为没有任何东西没有.Text属性。
Referencing array elements later will result in an NRE. If you do this in Form_Load
, due to an odd bug, the IDE may not report the exception when it happens. The exception will pop up later when your code tries to use the array. This "silent exception" is detailed in this post. For our purposes, the key is that when something catastrophic happens while creating a form (Sub New
or Form Load
event), exceptions may go unreported, the code exits the procedure and just displays the form.
稍后引用数组元素将导致NRE。如果在Form_Load中这样做,由于一个奇怪的错误,IDE可能不会在发生异常时报告异常。当代码试图使用数组时,异常会出现。这个“沉默的例外”在这个帖子里是详细的。对于我们的目的,关键是当在创建表单时发生了一些灾难性的事情(新的或表单加载事件),异常可能会被忽略,代码会退出过程并显示表单。
Since no other code in your Sub New
or Form Load
event will run after the NRE, a great many other things can be left uninitialized.
因为在您的子新或表单加载事件中没有其他代码会在NRE之后运行,所以很多其他的东西都可以不被初始化。
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Note this applies to any and all control and component references making these illegal where they are:
请注意,这适用于任何和所有控制和组件引用,使它们成为非法的地方:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Partial Remedy
部分解决
It is curious that VB does not provide a warning, but the remedy is to declare the containers at the form level, but initialize them in form load event handler when the controls do exist. This can be done in Sub New
as long as your code is after the InitializeComponent
call:
奇怪的是,VB没有提供警告,但是补救方法是在表单级别声明容器,但是当控件存在时,将它们初始化为form load事件处理程序。只要您的代码是在InitializeComponent调用之后,这就可以在Sub - New中完成:
' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String
' Form Load, Form Shown or Sub New:
'
' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...)
studentName = TextBox32.Text ' For simple control references
The array code may not be out of the woods yet. Any controls which are in a container control (like a GroupBox
or Panel
) will not be found in Me.Controls
; they will be in the Controls collection of that Panel or GroupBox. Nor will a control be returned when the control name is misspelled ("TeStBox2"
). In such cases, Nothing
will again be stored in those array elements and an NRE will result when you attempt to reference it.
数组代码可能还没有脱离险境。任何在容器控件中(如GroupBox或Panel)的控件都不会在me .控件中找到;它们将在该面板或GroupBox的控件集合中。当控件名称拼写错误(“TeStBox2”)时,控件也不会返回。在这种情况下,当您尝试引用它时,将不会再次存储这些数组元素和NRE。
These should be easy to find now that you know what you are looking for:
这些应该很容易找到,因为你知道你在寻找什么:
"Button2" resides on a Panel
“Button2”位于一个面板上。
Remedy
补救措施
Rather than indirect references by name using the form's Controls
collection, use the control reference:
使用控件引用,而不是使用表单控件集合的名称间接引用:
' Declaration
Private NameBoxes As TextBox()
' Initialization - simple and easy to read, hard to botch:
NameBoxes = New TextBox() {TextBox1, TextBox2, ...)
' Initialize a List
NamesList = New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})
' or
NamesList = New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})
Function Returning Nothing
Private bars As New List(Of Bars) ' Declared and created
Public Function BarList() As List(Of Bars)
bars.Clear
If someCondition Then
For n As Integer = 0 to someValue
bars.Add(GetBar(n))
Next n
Else
Exit Function
End If
Return bars
End Function
This is a case where the IDE will warn you that 'not all paths return a value and a NullReferenceException
may result'. You can suppress the warning, by replacing Exit Function
with Return Nothing
, but that does not solve the problem. Anything which tries to use the return when someCondition = False
will result in an NRE:
在这种情况下,IDE会警告您“不是所有路径返回一个值,而NullReferenceException可能会导致”。您可以通过替换Exit函数来抑制警告,但是这并不能解决问题。任何试图使用返回时,当someCondition = False时,将导致NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Remedy
补救措施
Replace Exit Function
in the function with Return bList
. Returning an empty List
is not the same as returning Nothing
. If there is a chance that a returned object can be Nothing
, test before using it:
用Return bList替换函数中的Exit函数。返回空列表不等同于返回空列表。如果返回的对象不可能是空的,则在使用它之前进行测试:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Poorly Implemented Try/Catch
A badly implemented Try/Catch can hide where the problem is and result in new ones:
一个被严重执行的Try/Catch可以隐藏问题所在,并导致新的问题:
Dim dr As SqlDataReader
Try
Dim lnk As LinkButton = TryCast(sender, LinkButton)
Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username") = eid
sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username='" & eid & "'"
If connection.State <> ConnectionState.Open Then
connection.Open()
End If
command = New SqlCommand(sqlQry, connection)
'More code fooing and barring
dr = command.ExecuteReader()
If dr.Read() Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))
...
End If
mpe.Show()
Catch
Finally
command.Dispose()
dr.Close() ' <-- NRE
connection.Close()
End Try
This is a case of an object not being created as expected, but also demonstrates the counter usefulness of an empty Catch
.
这是一个不像预期的那样创建对象的情况,但也演示了空捕获的计数器有用性。
There is an extra comma in the SQL (after 'mailaddress') which results in an exception at .ExecuteReader
. After the Catch
does nothing, Finally
tries to perform clean up, but since you cannot Close
a null DataReader
object, a brand new NullReferenceException
results.
SQL中有一个额外的逗号(在“mailaddress”之后),这将导致. executereader异常。捕获后什么都不做,最后尝试执行清理,但是由于您不能关闭空DataReader对象,一个全新的NullReferenceException结果。
An empty Catch
block is the devil's playground. This OP was baffled why he was getting an NRE in the Finally
block. In other situations, an empty Catch
may result in something else much further downstream going haywire and cause you to spend time looking at the wrong things in the wrong place for the problem. (The "silent exception" described above provides the same entertainment value.)
一个空的挡块是魔鬼的游乐场。这个OP被搞糊涂了,为什么他在最后一个街区得到了一个NRE。在其他情况下,一个空的捕获可能会导致其他一些更下游的事情失控,导致你花时间在错误的地方查看错误的事情。(上面描述的“静默例外”提供了相同的娱乐价值。)
Remedy
补救措施
Don't use empty Try/Catch blocks - let the code crash so you can a) identify the cause b) identify the location and c) apply a proper remedy. Try/Catch blocks are not intended to hide exceptions from the person uniquely qualified to fix them - the developer.
不要使用空的Try/Catch块——让代码崩溃,这样你就可以a)识别原因b)确定位置和c)应用适当的补救方法。Try/Catch块的目的不是为了隐藏特定于修复它们的人的异常——开发人员。
DBNull is not the same as Nothing
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
The IsDBNull
function is used to test if a value equals System.DBNull
: From MSDN:
IsDBNull函数用于测试一个值是否等于系统。从MSDN DBNull::
The System.DBNull value indicates that the Object represents missing or non-existent data. DBNull is not the same as Nothing, which indicates that a variable has not yet been initialized.
这个系统。DBNull值表示对象表示丢失或不存在的数据。DBNull不等同于Nothing,这表明变量还没有初始化。
Remedy
补救措施
If row.Cells(0) IsNot Nothing Then ...
As before, you can test for Nothing, then for a specific value:
如前所述,您可以对任何东西进行测试,然后对特定的值进行测试:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Example 2
示例2
Dim getFoo = (From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
If Not IsDBNull(getFoo) Then
If IsDBNull(getFoo.user_id) Then
txtFirst.Text = getFoo.first_name
Else
...
FirstOrDefault
returns the first item or the default value, which is Nothing
for reference types and never DBNull
:
FirstOrDefault返回第一个项或默认值,这对于引用类型来说是没有意义的,也不会返回DBNull:
If getFoo IsNot Nothing Then...
Controls
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
If a CheckBox
with chkName
can't be found (or exists in a GroupBox
), then chk
will be Nothing and be attempting to reference any property will result in an exception.
如果无法找到带有chkName的复选框(或在GroupBox中存在),则chk将不存在,并试图引用任何属性将导致异常。
Remedy
补救措施
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
The DataGridView
The DGV has a few quirks seen periodically:
DGV有一些周期性的怪癖:
dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"
If dgvBooks
has AutoGenerateColumns = True
, it will create the columns, but it does not name them, so the above code fails when it references them by name.
如果dgvBooks具有AutoGenerateColumns = True,它将创建列,但它不命名它们,因此当它引用它们的名称时,上面的代码会失败。
Remedy
补救措施
Name the columns manually, or reference by index:
手动命名列,或通过索引引用:
dgvBooks.Columns(0).Visible = True
Example 2 — Beware of the NewRow
xlWorkSheet = xlWorkBook.Sheets("sheet1")
For i = 0 To myDGV.RowCount - 1
For j = 0 To myDGV.ColumnCount - 1
For k As Integer = 1 To myDGV.Columns.Count
xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
Next
Next
Next
When your DataGridView
has AllowUserToAddRows
as True
(the default), the Cells
in the blank/new row at the bottom will all contain Nothing
. Most attempts to use the contents (for example, ToString
) will result in an NRE.
当DataGridView允许usertoaddrows为True(默认值)时,位于底部的空/新行中的单元格将全部不包含任何内容。大多数尝试使用内容(例如,ToString)都会导致NRE。
Remedy
补救措施
Use a For/Each
loop and test the IsNewRow
property to determine if it is that last row. This works whether AllowUserToAddRows
is true or not:
使用For/Each循环并测试IsNewRow属性,以确定它是否是最后一行。无论AllowUserToAddRows是否为真,这都是可行的:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
If you do use a For n
loop, modify the row count or use Exit For
when IsNewRow
is true.
如果您确实使用For n循环,那么在IsNewRow为真时,修改行计数或使用Exit。
My.Settings (StringCollection)
Under certain circumstances, trying to use an item from My.Settings
which is a StringCollection
can result in a NullReference the first time you use it. The solution is the same, but not as obvious. Consider:
在某些情况下,试图使用我的物品。设置是一个StringCollection,可以在第一次使用它时产生NullReference。解决方案是一样的,但不是很明显。考虑:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Since VB is managing Settings for you, it is reasonable to expect it to initialize the collection. It will, but only if you have previously added an initial entry to the collection (in the Settings editor). Since the collection is (apparently) initialized when an item is added, it remains Nothing
when there are no items in the Settings editor to add.
由于VB是为您管理设置,因此期望它初始化集合是合理的。它将会,但前提是您之前添加了一个初始条目到集合(在设置编辑器中)。因为在添加一个项时,集合(显然)是初始化的,所以在设置编辑器中没有添加任何项时,它仍然是空的。
Remedy
补救措施
Initialize the settings collection in the form's Load
event handler, if/when needed:
如果需要,在表单的加载事件处理程序中初始化设置集合:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Typically, the Settings
collection will only need to be initialized the first time the application runs. An alternate remedy is to add an initial value to your collection in Project -> Settings | FooBars, save the project, then remove the fake value.
通常,设置集合只需要在应用程序第一次运行时初始化。另一种补救方法是在项目->设置| FooBars中添加一个初始值,保存项目,然后删除假值。
Key Points
You probably forgot the New
operator.
你可能忘记了新的接线员。
or
或
Something you assumed would perform flawlessly to return an initialized object to your code, did not.
您假定的某些东西将完美地执行,以返回初始化的对象到您的代码,但没有。
Don't ignore compiler warnings (ever) and use Option Strict On
(always).
不要忽略编译器警告(永远),并严格使用选项(总是)。
MSDN NullReference例外
#3
208
Another scenario is when you cast a null object into a value type. For example, the code below:
另一种情况是将null对象转换为值类型。例如,下面的代码:
object o = null;
DateTime d = (DateTime)o;
It will throw a NullReferenceException
on the cast. It seems quite obvious in the above sample, but this can happen in more "late-binding" intricate scenarios where the null object has been returned from some code you don't own, and the cast is for example generated by some automatic system.
它将在cast上抛出一个NullReferenceException。在上面的示例中,这似乎很明显,但是这可能发生在更“后期绑定”的复杂场景中,在这里,null对象从一些您不拥有的代码中返回,而cast是由一些自动系统生成的。
One example of this is this simple ASP.NET binding fragment with the Calendar control:
一个例子就是这个简单的ASP。与日历控件的网络绑定片段:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Here, SelectedDate
is in fact a property - of DateTime
type - of the Calendar
Web Control type, and the binding could perfectly return something null. The implicit ASP.NET Generator will create a piece of code that will be equivalent to the cast code above. And this will raise a NullReferenceException
that is quite difficult to spot, because it lies in ASP.NET generated code which compiles fine...
这里,SelectedDate实际上是日历Web控件类型的DateTime类型的属性,绑定可以完美地返回null。隐式的ASP。NET生成器将创建一个与上面的cast代码等价的代码。这将会引发一个NullReferenceException异常,因为它位于ASP中。NET生成的代码,编译好的…
#4
139
It means that the variable in question is pointed at nothing. I could generate this like so:
这意味着问题中的变量没有指向任何东西。我可以这样生成:
SqlConnection connection = null;
connection.Open();
That will throw the error because while I've declared the variable "connection
", it's not pointed to anything. When I try to call the member "Open
", there's no reference for it to resolve, and it will throw the error.
这将抛出错误,因为当我声明变量“connection”时,它并没有指向任何东西。当我尝试调用成员“Open”时,没有对它进行解析的引用,它会抛出错误。
To avoid this error:
为了避免这个错误:
- Always initialize your objects before you try to do anything with them.
- 在尝试使用它们之前,总是先初始化对象。
- If you're not sure whether the object is null, check it with
object == null
. - 如果您不确定该对象是否为空,请用object == null检查它。
JetBrains' Resharper tool will identify every place in your code that has the possibility of a null reference error, allowing you to put in a null check. This error is the number one source of bugs, IMHO.
JetBrains的Resharper工具将识别代码中所有可能出现空引用错误的地方,允许您进行空检查。这个错误是bug的头号来源,IMHO。
#5
131
It means your code used an object reference variable that was set to null (i.e. it did not reference an actual object instance).
这意味着您的代码使用的对象引用变量被设置为null(即它没有引用实际的对象实例)。
To prevent the error, objects that could be null should be tested for null before being used.
为了防止错误,可以在使用null之前对可能为null的对象进行测试。
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
#6
86
Be aware that regardless of the scenario, the cause is always the same in .NET:
请注意,无论场景如何,在。net中,原因总是相同的:
You are trying to use a reference variable whose value is
Nothing
/null
. When the value isNothing
/null
for the reference variable, that means it is not actually holding a reference to an instance of any object that exists on the heap.您正在尝试使用一个值为零的引用变量。当引用变量的值为零/null时,这意味着它实际上并没有对存在于堆上的任何对象的实例进行引用。
You either never assigned something to the variable, never created an instance of the value assigned to the variable, or you set the variable equal to
Nothing
/null
manually, or you called a function that set the variable toNothing
/null
for you.您要么从来没有给变量赋值,也没有创建赋给变量的值的实例,或者您将变量设置为空值/null,或者您调用了一个函数,该函数将变量设置为Nothing/null。
#7
73
An example of this exception being thrown is: When you are trying to check something, that is null.
抛出这个异常的一个例子是:当您试图检查某个东西时,它是空的。
For example:
例如:
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
The .NET runtime will throw a NullReferenceException when you attempt to perform an action on something which hasn't been instantiated i.e. the code above.
当您试图对未实例化的对象执行操作时,. net运行时将抛出一个NullReferenceException,即上面的代码。
In comparison to an ArgumentNullException which is typically thrown as a defensive measure if a method expects that what is being passed to it is not null.
与通常作为防御措施抛出的ArgumentNullException相比,如果方法期望传递给它的值不是null。
More information is in C# NullReferenceException and Null Parameter.
更多信息在c# NullReferenceException和Null参数中。
#8
67
If you have not initialized a reference type, and you want to set or read one of its properties, it will throw a NullReferenceException.
如果没有初始化引用类型,并且希望设置或读取它的一个属性,它将抛出一个NullReferenceException。
Example:
例子:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
You can simply avoid this by checking if the variable is not null:
您可以通过检查变量是否为null来避免这一点:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
To fully understand why a NullReferenceException is thrown, it is important to know the difference between value types and reference types.
要完全理解为什么会抛出NullReferenceException,重要的是要知道值类型和引用类型之间的区别。
So, if you're dealing with value types, NullReferenceExceptions can not occur. Though you need to keep alert when dealing with reference types!
因此,如果您正在处理值类型,则不可能出现nullreferenceexception。虽然您需要在处理引用类型时保持警惕!
Only reference types, as the name is suggesting, can hold references or point literally to nothing (or 'null'). Whereas value types always contain a value.
只有引用类型,顾名思义,可以保存引用或指向任何东西(或“null”)。而值类型总是包含一个值。
Reference types (these ones must be checked):
引用类型(必须检查这些类型):
- dynamic
- 动态
- object
- 对象
- string
- 字符串
Value types (you can simply ignore these ones):
值类型(您可以忽略这些类型):
- Numeric types
- 数值类型
- Integral types
- 积分类型
- Floating-point types
- 浮点类型
- decimal
- 小数
- bool
- bool
- User defined structs
- 用户定义的结构体
#9
62
Another case where NullReferenceExceptions
can happen is the (incorrect) use of the as
operator:
nullreferenceexception可能发生的另一种情况是(不正确的)使用as操作符:
class Book {
public string Name { get; set; }
}
class Car { }
Car mycar = new Car();
Book mybook = mycar as Book; // Incompatible conversion --> mybook = null
Console.WriteLine(mybook.Name); // NullReferenceException
Here, Book
and Car
are incompatible types; a Car
cannot be converted/cast to a Book
. When this cast fails, as
returns null
. Using mybook
after this causes a NullReferenceException
.
在这里,书和车是不兼容的类型;汽车不能转换成一本书。当这个cast失败时,返回null。在此之后使用mybook将导致NullReferenceException。
In general, you should use a cast or as
, as follows:
一般来说,你应该使用一个cast或as,如下:
If you are expecting the type conversion to always succeed (ie. you know what the object should be ahead of time), then you should use a cast:
如果您期望类型转换总是成功的(ie)。你知道什么东西应该提前,然后你应该使用一个演员:
ComicBook cb = (ComicBook)specificBook;
If you are unsure of the type, but you want to try to use it as a specific type, then use as
:
如果您不确定该类型,但是您想尝试将其作为特定类型使用,然后使用as:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
#10
57
You are using the object that contains the null value reference. So it's giving a null exception. In the example the string value is null and when checking its length, the exception occurred.
您正在使用包含空值引用的对象。它给出了一个空异常。在示例中,字符串值为null,当检查其长度时,异常发生。
Example:
例子:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
The exception error is:
异常的错误是:
Unhandled Exception:
未处理的例外:
System.NullReferenceException: Object reference not set to an instance of an object. at Program.Main()
系统。NullReferenceException:对象引用没有设置为对象的实例。在Program.Main()
#11
45
Simon Mourier gave this example:
Simon Mourier给出了这个例子:
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
where an unboxing conversion (cast) from object
(or from one of the classes System.ValueType
or System.Enum
, or from an interface type) to a value type (other than Nullable<>
) in itself gives the NullReferenceException
.
从对象(或从一个类系统中)进行非装箱转换(cast)的地方。ValueType或系统。枚举(或从接口类型)到值类型(除了Nullable<>)本身提供了NullReferenceException。
In the other direction, a boxing conversion from a Nullable<>
which has HasValue
equal to false
to a reference type, can give a null
reference which can then later lead to a NullReferenceException
. The classic example is:
在另一个方向上,从一个可空的<>,它的值等于false到引用类型的一个装箱转换,可以给出一个空引用,然后可以导致一个NullReferenceException。典型的例子是:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Sometimes the boxing happens in another way. For example with this non-generic extension method:
有时,拳击会以另一种方式发生。例如,使用这种非通用的扩展方法:
public static void MyExtension(this object x)
{
x.ToString();
}
the following code will be problematic:
下面的代码会有问题:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
These cases arise because of the special rules the runtime uses when boxing Nullable<>
instances.
这些情况出现的原因是,运行时使用的特殊规则会在装箱时使用无效的<>实例。
#12
37
While what causes a NullReferenceExceptions and approaches to avoid/fix such an exception have been addressed in other answers, what many programmers haven't learned yet is how to independently debug such exceptions during development.
虽然导致nullreferenceexception的原因和避免/修复此类异常的方法已经在其他答案中得到解决,但是许多程序员还没有学会如何在开发过程中独立地调试这些异常。
In Visual Studio this is usually easy thanks to the Visual Studio Debugger.
在Visual Studio中,这通常要归功于Visual Studio调试器。
First, make sure that the correct error is going to be caught - see How do I allow breaking on 'System.NullReferenceException' in VS2010? Note1
首先,确保正确的错误将被捕获——看看我如何允许中断系统。在VS2010得到NullReferenceException’?注一
Then either Start with Debugging (F5) or Attach [the VS Debugger] to Running Process. On occasion it may be useful to use Debugger.Break
, which will prompt to launch the debugger.
然后,要么从调试(F5)开始,要么将[VS调试器]附加到运行进程。有时,使用调试器可能是有用的。中断,它将提示启动调试器。
Now, when the NullReferenceException is thrown (or unhandled) the debugger will stop (remember the rule set above?) on the line on which the exception occurred. Sometimes the error will be easy to spot.
现在,当抛出(或未处理)NullReferenceException时,调试器将停止(记住上面的规则集),而在该异常发生的行上。有时这个错误很容易被发现。
For instance, in the following line the only code that can cause the exception is if myString
evaluates to null. This can be verified by looking at the Watch Window or running expressions in the Immediate Window.
例如,在下面一行中,唯一可能导致异常的代码是如果myString计算为null。这可以通过查看表窗口或直接窗口中的运行表达式来验证。
var x = myString.Trim();
In more advanced cases, such as the following, you'll need to use one of the techniques above (Watch or Immediate Windows) to inspect the expressions to determine if str1
was null or if str2
was null.
在更高级的情况下,比如下面的例子,您需要使用上面的技术之一(观察或直接窗口)来检查表达式,以确定str1是否为null,或者str2是否为null。
var x = str1.Trim() + str2.Trim();
Once where the exception is throw has been located, it's usually trivial to reason backwards to find out where the null value was [incorrectly] introduced --
一旦抛出异常的位置,通常就会很容易地找出null值(错误地)引入的地方。
Take the time required to understand the cause of the exception. Inspect for null expressions. Inspect the previous expressions which could have resulted in such null expressions. Add breakpoints and step through the program as appropriate. Use the debugger.
花时间去了解异常的原因。检查空表达式。检查之前可能导致这种空表达式的表达式。在适当的时候添加断点和步骤。使用调试器。
1 If Break on Throws is too aggressive and the debugger stops on an NPE in the .NET or 3rd-party library, Break on User-Unhandled can be used to limit the exceptions caught. Additionally, VS2012 introduces Just My Code which I recommend enabling as well.
如果在. net或3rd-party库中,如果中断的攻击太过激烈,调试器停止在NPE上,则可以使用用户未处理的中断来限制捕获的异常。另外,VS2012只介绍了我建议启用的代码。
If you are debugging with Just My Code enabled, the behavior is slightly different. With Just My Code enabled, the debugger ignores first-chance common language runtime (CLR) exceptions that are thrown outside of My Code and do not pass through My Code
如果您正在调试仅启用了我的代码,则行为略有不同。在启用了我的代码之后,调试器将忽略在我的代码之外抛出的第一个常见语言运行时(CLR)异常,并且不通过我的代码。
#13
35
Adding a case when the class name for entity used in entity framework is same as class name for a web form code-behind file.
当实体框架中使用的实体的类名与web表单代码后文件的类名相同时,添加一个case。
Suppose you have a web form Contact.aspx whose codebehind class is Contact and you have an entity name Contact.
假设您有一个web表单联系人。它的codebehind类是Contact,并且您有一个实体名称Contact。
Then following code will throw a NullReferenceException when you call context.SaveChanges()
然后,当您调用context.SaveChanges()时,下面的代码将抛出一个NullReferenceException。
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
For the sake of completeness DataContext class
为了完整的DataContext类。
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
and Contact entity class. Sometimes entity classes are partial classes so that you can extend them in other files too.
和联系实体类。有时,实体类是部分类,因此您也可以将它们扩展到其他文件中。
public partial class Contact
{
public string Name {get; set;}
}
The error occurs when both the entity and codebehind class are in same namespace. To fix this, rename the entity class or the codebehind class for Contact.aspx.
当实体和codebehind类都在同一个名称空间中时,就会出现错误。要修复这个问题,将实体类重命名为Contact.aspx的代码后类。
Reason I am still not sure about the reason. But whenever any of the entity class will extend System.Web.UI.Page this error occurs.
原因我还是不太清楚。但无论何时,任何实体类都将扩展System.Web.UI。页面会发生此错误。
For discussion have a look at NullReferenceException in DbContext.saveChanges()
对于讨论,请查看DbContext.saveChanges()中的NullReferenceException
#14
34
Another general case where one might receive this exception involves mocking classes during unit testing. Regardless of the mocking framework being used, you must ensure that all appropriate levels of the class hierarchy are properly mocked. In particular, all properties of HttpContext
which are referenced by the code under test must be mocked.
另一个常见的情况是,在单元测试期间,可能会收到这个异常的模拟类。不管使用了什么mock框架,都必须确保正确地模拟了类层次结构的所有适当级别。特别是,在测试代码中引用的HttpContext的所有属性都必须被嘲笑。
See "NullReferenceException thrown when testing custom AuthorizationAttribute" for a somewhat verbose example.
参见“在测试自定义AuthorizationAttribute时抛出的NullReferenceException”,这是一个有点冗长的示例。
#15
33
I have a different perspective to answering this. This sort of answers "what else can I do to avoid it?"
我对此有不同的看法。这样的回答“我还能做些什么来避免它呢?”
When working across different layers, for example in an MVC application, a controller needs services to call business operations. In such scenarios Dependency Injection Container can be used to initialize the services to avoid the NullReferenceException. So that means you don't need to worry about checking for null and just call the services from the controller as though they will always to available (and initialized) as either a singleton or a prototype.
当跨不同的层工作时,例如在MVC应用程序中,控制器需要服务来调用业务操作。在这种情况下,可以使用依赖注入容器来初始化服务,以避免NullReferenceException。因此,这意味着您不必担心检查null值,只需从控制器调用服务,就像它们将始终可用(并初始化)作为单例或原型一样。
public class MyController
{
private ServiceA serviceA;
private ServiceB serviceB;
public MyController(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void MyMethod()
{
// We don't need to check null because the dependency injection container
// injects it, provided you took care of bootstrapping it.
var someObject = serviceA.DoThis();
}
}
#16
31
On the matter of "what should I do about it", there can be many answers.
关于“我该怎么做”的问题,可以有很多答案。
A more "formal" way of preventing such error conditions while developing is applying design by contract in your code. This means you need to set class invariants, and/or even function/method preconditions and postconditions on your system, while developing.
在开发过程中,一种更“正式”的方法来防止这样的错误情况,这是在代码中应用契约式设计。这意味着您需要在开发过程中设置类不变量,以及/或甚至函数/方法前置条件和后置条件。
In short, class invariants ensure that there will be some constraints in your class that will not get violated in normal use (and therefore, the class will not get in an inconsistent state). Preconditions mean that data given as input to a function/method must follow some constraints set and never violate them, and postconditions mean that a function/method output must follow the set constraints again without ever violating them. Contract conditions should never be violated during execution of a bug-free program, therefore design by contract is checked in practice in debug mode, while being disabled in releases, to maximize the developed system performance.
简而言之,类不变量确保在您的类中有一些约束不会在正常使用中被违背(因此,该类不会处于不一致的状态)。前提条件是,作为函数/方法输入的数据必须遵循一定的约束条件,且不可违背,而postconditions意味着函数/方法输出必须再次遵循设置约束,而不会违反它们。在没有bug的程序执行过程中,不应该违反合同条件,因此,在调试模式下,在调试模式下进行设计,同时在发布中禁用,以最大化开发系统的性能。
This way, you can avoid NullReferenceException
cases that are results of violation of the constraints set. For example, if you use an object property X
in a class and later try to invoke one of its methods and X
has a null value, then this will lead to NullReferenceException
:
通过这种方式,您可以避免NullReferenceException异常,这是对约束集的违反结果。
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
But if you set "property X must never have a null value" as method precondition, then you can prevent the scenario described before:
但是,如果您设置“属性X必须永远没有空值”作为方法前提条件,那么您可以防止前面描述的场景:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
For this cause, Code Contracts project exists for .NET applications.
对于这个原因,. net应用程序存在代码契约项目。
Alternatively, design by contract can be applied using assertions.
或者,可以使用断言来应用契约式设计。
UPDATE: It is worth mentioning that the term was coined by Bertrand Meyer in connection with his design of the Eiffel programming language.
更新:值得一提的是,这个词是由Bertrand Meyer和他设计的埃菲尔编程语言创造的。
#17
30
A NullReferenceException
is thrown when we are trying to access Properties of a null object or when a string value becomes empty and we are trying to access string methods.
当我们试图访问null对象的属性或字符串值变为空时,我们尝试访问字符串方法时抛出一个NullReferenceException。
For example:
例如:
-
When a string method of an empty string accessed:
当被访问的空字符串的字符串方法:
string str = string.Empty; str.ToLower(); // throw null reference exception
-
When a property of a null object accessed:
当一个空对象的属性被访问:
Public Class Person { public string Name { get; set; } } Person objPerson; objPerson.Name /// throw Null refernce Exception
#18
26
TL;DR: Try using Html.Partial
instead of Renderpage
TL;博士:尝试使用Html。部分代替Renderpage
I was getting Object reference not set to an instance of an object
when I tried to render a View within a View by sending it a Model, like this:
当我试图通过发送一个模型来呈现视图时,我得到的对象引用没有设置为对象的实例,就像这样:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Debugging showed the model was Null inside MyOtherView. Until I changed it to:
调试显示模型在MyOtherView中为Null。直到我把它改成:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
And it worked.
它工作。
Furthermore, the reason I didn't have Html.Partial
to begin with was because Visual Studio sometimes throws error-looking squiggly lines under Html.Partial
if it's inside a differently constructed foreach
loop, even though it's not really an error:
此外,我没有Html的原因。部分开始是因为Visual Studio有时会在Html下抛出错误的曲线。部分如果它在一个不同构造的foreach循环中,即使它不是一个真正的错误:
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
But I was able to run the application with no problems with this "error". I was able to get rid of the error by changing the structure of the foreach
loop to look like this:
但是我能够运行这个应用程序,并没有遇到这个“错误”。我可以通过改变foreach循环的结构来摆脱这个错误:
@foreach(var M in MyEntities){
...
}
Although I have a feeling it was because Visual Studio was misreading the ampersands and brackets.
虽然我感觉这是因为Visual Studio误读了ampersands和括号。
#19
17
What can you do about it?
你能做些什么呢?
There is a lot of good answers here explaining what a null reference is and how to debug it. But there is very little on how to prevent the issue or at least make it easier to catch.
这里有很多很好的答案来解释空引用是什么以及如何调试它。但是,关于如何防止这个问题,或者至少让它更容易被抓住,几乎没有。
Check arguments
检查参数
For example, methods can check the different arguments to see if they are null and throw an ArgumentNullException
, an exception obviously created for this exact purpose.
例如,方法可以检查不同的参数,看看它们是否为null,并抛出一个ArgumentNullException,这显然是为这个目的而创建的异常。
The constructor for the ArgumentNullException
even takes the name of the parameter and a message as arguments so you can tell the developer exactly what the problem is.
ArgumentNullException的构造函数甚至将参数的名称和一个消息作为参数,这样您就可以确切地告诉开发人员问题是什么。
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Use Tools
使用工具
There are also several libraries that can help. "Resharper" for example can provide you with warnings while you are writing code, especially if you use their attribute: NotNullAttribute
还有一些库可以提供帮助。例如,“Resharper”可以在你编写代码时向你提供警告,特别是如果你使用他们的属性:NotNullAttribute。
There's "Microsoft Code Contracts" where you use syntax like Contract.Requires(obj != null)
which gives you runtime and compile checking: Introducing Code Contracts.
这里有“微软代码契约”,你可以使用类似于契约的语法。需要(obj != null),它提供运行时和编译检查:引入代码契约。
There's also "PostSharp" which will allow you to just use attributes like this:
还有“PostSharp”,它允许你只使用这样的属性:
public void DoSometing([NotNull] obj)
By doing that and making PostSharp part of your build process obj
will be checked for null at runtime. See: PostSharp null check
通过这样做,将在运行时检查您的构建过程的后半部分。看:PostSharp null检查
Plain Code Solution
纯代码解决方案
Or you can always code your own approach using plain old code. For example here is a struct that you can use to catch null references. It's modeled after the same concept as Nullable<T>
:
或者您也可以使用简单的旧代码编写自己的方法。例如,这里有一个结构,您可以使用它来捕获空引用。它的模型与Nullable
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
You would use very similar to the same way you would use Nullable<T>
, except with the goal of accomplishing exactly the opposite - to not allow null
. Here are some examples:
您将使用非常类似于使用Nullable
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
is implicitly cast to and from T
so you can use it just about anywhere you need it. For example, you can pass a Person
object to a method that takes a NotNull<Person>
:
NotNull< t>被隐式地转换为T,因此您可以在任何需要的地方使用它。例如,您可以将Person对象传递给一个方法,该方法接受NotNull
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
As you can see above as with nullable you would access the underlying value through the Value
property. Alternatively, you can use an explicit or implicit cast, you can see an example with the return value below:
正如您可以在上面看到的那样,可以通过值属性访问潜在的值。或者,您可以使用显式或隐式转换,您可以看到一个带有返回值的示例:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Or you can even use it when the method just returns T
(in this case Person
) by doing a cast. For example, the following code would just like the code above:
或者您甚至可以在方法返回T(在本例中为Person)时使用它。例如,下面的代码就像上面的代码:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combine with Extension
结合扩展
Combine NotNull<T>
with an extension method and you can cover even more situations. Here is an example of what the extension method can look like:
将NotNull< t>与扩展方法结合起来,您可以覆盖更多的情况。下面是一个扩展方法的示例:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
And here is an example of how it could be used:
这里有一个例子,说明如何使用它:
var person = GetPerson().NotNull();
GitHub
GitHub
For your reference I made the code above available on GitHub, you can find it at:
为了您的参考,我在GitHub上提供了以上代码,您可以在:
https://github.com/luisperezphd/NotNull
https://github.com/luisperezphd/NotNull
Related Language Feature
相关的语言功能
C# 6.0 introduced the "null-conditional operator" that helps with this a little. With this feature, you can reference nested objects and if any one of them is null
the whole expression returns null
.
c# 6.0引入了“空条件操作符”,它可以帮助解决这个问题。有了这个特性,就可以引用嵌套对象,如果其中任何一个都是null,那么整个表达式将返回null。
This reduces the number of null checks you have to do in some cases. The syntax is to put a question mark before each dot. Take the following code for example:
这减少了在某些情况下必须执行的空检查的数量。语法是在每个点之前加一个问号。以下列代码为例:
var address = country?.State?.County?.City;
Imagine that country
is an object of type Country
that has a property called State
and so on. If country
, State
, County
, or City
is null
then address will be
null. Therefore you only have to check whether
addressis
null`.
假设国家是一个国家的对象,它有一个属性叫State,等等。如果国家、州、县或城市是空的,那么地址将会是benull。因此,你只需要检查一下是否有问题。
It's a great feature, but it gives you less information. It doesn't make it obvious which of the 4 is null.
这是一个很棒的功能,但它给你的信息更少。这并不能说明4的哪个是空的。
Built-in like Nullable?
内置可空吗?
C# has a nice shorthand for Nullable<T>
, you can make something nullable by putting a question mark after the type like so int?
.
c#对于Nullable
It would be nice if C# had something like the NotNull<T>
struct above and had a similar shorthand, maybe the exclamation point (!) so that you could write something like: public void WriteName(Person! person)
.
如果c#有一些类似于NotNull< t>结构的东西,并且有类似的简写,也许是感叹号(!),这样你就可以写一些东西:public void WriteName(人!人)。
#20
6
You can fix NullReferenceException in a clean way using Null-conditional Operators in c#6 and write less code to handle null checks.
您可以使用c#6中的空条件操作符以一种干净的方式修复NullReferenceException,并编写更少的代码来处理null检查。
It's used to test for null before performing a member access (?.) or index (?[) operation.
在执行成员访问(?)或索引(?)操作之前,它用于测试null。
Example
例子
var name = p?.Spouse?.FirstName;
is equivalent to:
等价于:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
The result is that the name will be null when p is null or when p.Spouse is null.
结果是当p为null或p时,名称将为null。配偶是null。
Otherwise, the variable name will be assigned the value of the p.Spouse.FirstName.
否则,变量名将被赋值给p.Spouse.FirstName。
For More details : Null-conditional Operators
更多细节:空条件操作符。
#21
5
The error line "Object reference not set to an instance of an object. " states that you have not assigned instance object to a object reference and still you are accessing properies/methods of that object.
错误行“对象引用没有设置为对象的实例。“声明您没有将实例对象分配给对象引用的状态,并且您仍然在访问该对象的属性/方法。
for example: let say you have a class called myClass and it contains one property prop1.
例如:假设您有一个名为myClass的类,它包含一个属性prop1。
public Class myClass
{
public int prop1 {get;set;}
}
Now you are accessing this prop1 in some other class just like below:
现在你在其他类中访问这个prop1,就像下面这样:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
above line throws error because reference of class myClass is declared but not instantiated or an instance of object is not assigned to referecne of that class.
上面的行抛出错误,因为声明了类myClass的引用,但是没有实例化或对象的实例没有被分配给该类的引用。
To fix this you have to instantiate (assign object to reference of that class).
要修复这个问题,您必须实例化(分配对象以引用该类)。
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
#22
5
Interestingly, none of the answers on this page mention the two edge cases, hope no one minds if I add them:
有趣的是,在这个页面上没有一个答案提到这两个边缘案例,希望我添加它们时没有人会介意:
Edge case #1: concurrent access to a Dictionary
Generic dictionaries in .NET are not thread-safe and they sometimes might throw a NullReference
or even (more frequent) a KeyNotFoundException
when you try to access a key from two concurrent threads. The exception is quite misleading in this case.
. net中的通用字典不是线程安全的,有时候,当您试图从两个并发线程访问密钥时,它们可能会抛出一个NullReference甚至(更频繁地)一个KeyNotFoundException。在这种情况下,这个例外是很有误导性的。
Edge case #2: unsafe code
If a NullReferenceException
is thrown by unsafe
code, you might look at your pointer variables, and check them for IntPtr.Zero
or something. Which is the same thing ("null pointer exception"), but in unsafe code, variables are often cast to value-types/arrays, etc., and you bang your head against the wall, wondering how a value-type can throw this exception.
如果一个NullReferenceException被不安全的代码抛出,您可能会查看您的指针变量,并检查它们的IntPtr。零个或一些东西。也就是“空指针异常”,但是在不安全的代码中,变量通常被转换成值类型/数组等,然后你将头撞到墙上,想知道一个值类型如何抛出这个异常。
(Another reason for non-using unsafe code unless you need it, by the way)
(另一个不使用不安全代码的原因,除非你需要它)
#23
1
NullReferenceException or Object reference not set to an instance of an object occurs when an object of the class you are trying to use is not instantiated. For example:
当您试图使用的类的对象没有实例化时,不设置为对象实例的NullReferenceException或对象引用。例如:
Assume that you have a class named Student.
假设您有一个名为Student的类。
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Now, consider another class where you are trying to retrieve the student's full name.
现在,考虑另一个类,您正在尝试检索学生的全名。
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
As seen in the above code, the statement Student s - only declares the variable of type Student, note that the Student class is not instantiated at this point. Hence, when the statement s.GetFullName() gets executed, it will throw the NullReferenceException.
正如上面的代码中所看到的,语句学生只声明了类型Student的变量,注意到Student类在这一点上没有实例化。因此,当语句s.GetFullName()被执行时,它将抛出NullReferenceException。
#24
0
Well, in simple terms:
好吧,简单地说:
You are trying to access an object that isn't created or currently not in memory.
您正在尝试访问一个没有创建或当前没有内存的对象。
So how to tackle this:
如何解决这个问题:
-
Debug and let the debugger break... It will directly take you to the variable that is broken... Now your task is to simply fix this.. Using the new keyword in the appropriate place.
调试并让调试器中断…它会直接把你带到被破坏的变量…现在你的任务就是解决这个问题。在适当的位置使用新关键字。
-
If it is caused on some database commands because the object isn't present then all you need to do is do a null check and handle it:
如果它在某些数据库命令上引起,因为对象不存在,那么您所需要做的就是做一个空检查并处理它:
if (i == null) { // Handle this }
-
The hardest one .. if the GC collected the object already... This generally occurs if you are trying to find an object using strings... That is, finding it by name of the object then it may happen that the GC might already cleaned it up... This is hard to find and will become quite a problem... A better way to tackle this is do null checks wherever necessary during the development process. This will save you a lot of time.
最难的一个。如果GC已经收集了对象…如果您试图使用字符串查找对象,通常会出现这种情况。也就是说,根据对象的名称找到它,GC可能已经清理了它……这很难找到,而且将成为一个相当大的问题……解决这一问题的更好方法是在开发过程中任何必要的地方进行空检查。这会节省你很多时间。
By finding by name I mean some framework allow you to FIndObjects using strings and the code might look like this: FindObject("ObjectName");
通过查找名称,我的意思是一些框架允许您使用字符串进行FIndObjects,而代码可能是这样的:FindObject(“ObjectName”);
#25
0
If we consider common scenarios where this exception can be thrown, accessing properties withing object at the top.
如果我们考虑可以抛出这个异常的常见场景,那么访问位于顶部的属性withing对象。
Ex:
例:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
in here , if address is null , then you will get NullReferenceException.
在这里,如果地址为空,那么您将获得NullReferenceException。
So, as a practice we should always use null check, before accessing properties in such objects (specially in generic)
因此,作为一种实践,在访问这些对象的属性之前,我们应该始终使用空检查(特别是在通用对象中)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
#26
0
Reference types default to null to indicate that they are not referencing any object. Hence, if you try and access the object that is being referenced and there isn't one, you will get a NullReferenceException.
引用类型默认为null,表示它们没有引用任何对象。因此,如果您尝试访问被引用的对象,并且没有一个对象,那么您将获得一个NullReferenceException。
For Ex:
为例:
SqlConnection connection = null;
connection.Open();
When you run this code, you will get :
当您运行此代码时,您将得到:
System.NullReferenceException: Object reference not set to an instance of an object.
You can avoid this error by coding like this:
你可以这样编码来避免这个错误:
if (connection != null){
connection.Open();
}
Note: In order to avoid this error you should always initialize your objects before you try to do anything with them.
注意:为了避免这个错误,您应该在尝试使用对象之前初始化对象。
#27
-1
It means you are trying to manipulate something which has reference but not yet initialized
The first thing to do here is check every instance created.
Use breakpoints , watches , inspect your varibale values.
Follow stack trace and search for exact row and column which is creating problem
这意味着你在尝试操作一些有引用但尚未初始化的东西,首先要检查创建的每个实例。使用断点、手表、检查您的变量值。跟踪堆栈跟踪并查找正在创建问题的行和列。
#28
-1
If one is getting this message during saving or compiling the build, just close all the files and then open any file to compile and save.
如果在保存或编译构建过程中收到此消息,只需关闭所有文件,然后打开任何文件以编译和保存。
For me the reason was that I had rename the file and old file was still open.
对我来说,原因是我重命名了文件,旧文件仍然是打开的。
#29
-1
To use methods and member of an object you first have to create that object. If you didn't create it (variable that should hold the object is not initialized), but you try to use it's methods or variables you'll get that error.
要使用方法和对象的成员,首先必须创建该对象。如果您没有创建它(应该保存该对象的变量没有初始化),但是您尝试使用它的方法或变量,您将会得到这个错误。
Sometime you may just forgot to do initialization.
有时你可能忘记了初始化。
Edited: new can't return null, but fire's exception when failed. Long time ago it was the case in some languages, but not any more. Thanks @John Saunders for pointing that out.
编辑:new不能返回空值,但失败时触发异常。很久以前,在某些语言中是这样的,但现在不再是了。感谢@John Saunders指出这一点。
#30
-1
Literally the easiest way to fix a NullReferenceExeption has two ways. If you have a GameObject for example with a script attached and a variable named rb (rigidbody) this variable will start null when you start your game.
This is why you get a NullReferenceExeption because the computer does not have data stored in that variable.
从字面上看,解决nullreferenceex的最简单方法有两种方法。如果您有一个带有脚本的GameObject和一个名为rb(刚体)的变量,当您开始游戏时,这个变量将开始为空。这就是为什么您会得到一个nullreferenceex,因为计算机没有存储在该变量中的数据。
I'll be using a RigidBody variable as an example.
We can add data really easily actually in a few ways:
我将使用刚体变量作为例子。我们可以很容易地在几个方面添加数据:
- Add a RigidBody to your object with AddComponent > Physics > Rigidbody
Then go into your script and typerb = GetComponent<Rigidbody>();
This line of code works best under yourStart()
orAwake()
functions. - 在您的对象中添加一个刚体,AddComponent >物理>刚体然后进入您的脚本,并输入rb = GetComponent< RigidBody >();这一行代码在您的启动()或唤醒()函数下工作得最好。
- You can add a component programmatically and assign the variable at the same time with one line of code:
rb = AddComponent<RigidBody>();
-
您可以以编程方式添加组件,并在同一时间用一行代码来分配变量:rb = AddComponent
();
Further Notes: If you want unity to add a component to your object and you might have forgotten to add one, you can type [RequireComponent(typeof(RigidBody))]
above your class declaration (the space below all of your usings).
Enjoy and have fun making games!
进一步说明:如果您希望unity为您的对象添加一个组件,并且您可能忘记添加一个组件,那么您可以在您的类声明(您的所有usings下面的空间)上键入[RequireComponent(typeof(RigidBody))]。尽情享受制作游戏的乐趣吧!
#1
1992
What is the cause?
Bottom Line
You are trying to use something that is null
(or Nothing
in VB.NET). This means you either set it to null
, or you never set it to anything at all.
您尝试使用的是null(或VB.NET中没有的)。这意味着您要么将其设置为null,要么您从未将其设置为任何值。
Like anything else, null
gets passed around. If it is null
in method "A", it could be that method "B" passed a null
to method "A".
像其他任何东西一样,null被传递。如果方法“A”中为null,则可能是方法“B”传递了null到方法“A”。
The rest of this article goes into more detail and shows mistakes that many programmers often make which can lead to a NullReferenceException
.
本文的其余部分将更详细地介绍,并指出许多程序员经常犯的错误,这些错误可能导致NullReferenceException。
More Specifically
The runtime throwing a NullReferenceException
always means the same thing: you are trying to use a reference, and the reference is not initialized (or it was once initialized, but is no longer initialized).
运行时抛出一个NullReferenceException总是意味着相同的事情:您正在尝试使用引用,并且引用没有初始化(或者它曾经被初始化,但是不再被初始化)。
This means the reference is null
, and you cannot access members (such as methods) through a null
reference. The simplest case:
这意味着引用是空的,并且不能通过空引用访问成员(比如方法)。最简单的例子:
string foo = null;
foo.ToUpper();
This will throw a NullReferenceException
at the second line because you can't call the instance method ToUpper()
on a string
reference pointing to null
.
这将在第二行中抛出一个NullReferenceException,因为您不能在一个指向null的字符串引用上调用实例方法ToUpper()。
Debugging
How do you find the source of a NullReferenceException
? Apart from looking at the exception itself, which will be thrown exactly at the location where it occurs, the general rules of debugging in Visual Studio apply: place strategic breakpoints and inspect your variables, either by hovering the mouse over their names, opening a (Quick)Watch window or using the various debugging panels like Locals and Autos.
如何找到NullReferenceException的源?除了看异常本身,这将被完全在它出现的位置,在Visual Studio调试应用的一般规则:战略断点和检查你的变量,通过鼠标盘旋在他们的名字,打开(快速)监视窗口或使用各种调试面板像当地人和汽车。
If you want to find out where the reference is or isn't set, right-click its name and select "Find All References". You can then place a breakpoint at every found location and run your program with the debugger attached. Every time the debugger breaks on such a breakpoint, you need to determine whether you expect the reference to be non-null, inspect the variable and and verify that it points to an instance when you expect it to.
如果您想要查找引用的位置或未设置的位置,请右键单击它的名称并选择“查找所有引用”。然后,您可以在每个找到的位置上放置一个断点,并使用附加的调试器运行您的程序。每次调试器在这样一个断点上断开时,您需要确定是否希望引用非空,检查变量,并验证它指向一个实例。
By following the program flow this way, you can find the location where the instance should not be null, and why it isn't properly set.
通过这种方式跟踪程序流,您可以找到实例不应该为null的位置,以及为什么它没有正确设置。
Examples
Some common scenarios where the exception can be thrown:
可以抛出异常的一些常见场景:
Generic
ref1.ref2.ref3.member
If ref1 or ref2 or ref3 is null, then you'll get a NullReferenceException
. If you want to solve the problem, then find out which one is null by rewriting the expression to its simpler equivalent:
如果ref1或ref2或ref3是null,那么您将获得一个NullReferenceException。如果你想要解决这个问题,那么你可以通过把表达式改写成简单的等价形式来找出哪个是空的:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
Specifically, in HttpContext.Current.User.Identity.Name
, the HttpContext.Current
could be null, or the User
property could be null, or the Identity
property could be null.
具体来说,在HttpContext.Current.User.Identity。名字,HttpContext。当前可以是null,或者用户属性可以是null,或者标识属性可以为null。
Indirect
public class Person {
public int Age { get; set; }
}
public class Book {
public Person Author { get; set; }
}
public class Example {
public void Foo() {
Book b1 = new Book();
int authorAge = b1.Author.Age; // You never initialized the Author property.
// there is no Person to get an Age from.
}
}
If you want to avoid the child (Person) null reference, you could initialize it in the parent (Book) object's constructor.
如果您想避免子(Person)空引用,您可以在父(Book)对象的构造函数中初始化它。
Nested Object Initializers
The same applies to nested object initializers:
同样适用于嵌套对象初始化器:
Book b1 = new Book { Author = { Age = 45 } };
This translates to
这个翻译
Book b1 = new Book();
b1.Author.Age = 45;
While the new
keyword is used, it only creates a new instance of Book
, but not a new instance of Person
, so the Author
the property is still null
.
虽然使用了新的关键字,但它只创建了一个新的Book实例,而不是Person的新实例,因此该属性仍然为null。
Nested Collection Initializers
public class Person {
public ICollection<Book> Books { get; set; }
}
public class Book {
public string Title { get; set; }
}
The nested collection initializers behave the same:
嵌套集合初始化器的行为相同:
Person p1 = new Person {
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
This translates to
这个翻译
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
The new Person
only creates an instance of Person
, but the Books
collection is still null
. The collection initializer syntax does not create a collection for p1.Books
, it only translates to the p1.Books.Add(...)
statements.
新来的人只创建Person的实例,但是书籍的集合仍然是空的。集合初始化语法不为p1创建集合。书籍,它只会翻译成p1.Books.Add(…)语句。
Array
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
Array Elements
Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
// initialized. There is no Person to set the Age for.
Jagged Arrays
long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
// Use array[0] = new long[2]; first.
Collection/List/Dictionary
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
Range Variable (Indirect/Deferred)
public class Person {
public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
// on the line above. "p" is null because the
// first element we added to the list is null.
Events
public class Demo
{
public event EventHandler StateChanged;
protected virtual void OnStateChanged(EventArgs e)
{
StateChanged(this, e); // Exception is thrown here
// if no event handlers have been attached
// to StateChanged event
}
}
Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
如果您用不同于本地的命名字段,您可能会意识到您从未初始化字段。
public class Form1 {
private Customer customer;
private void Form1_Load(object sender, EventArgs e) {
Customer customer = new Customer();
customer.Name = "John";
}
private void Button_Click(object sender, EventArgs e) {
MessageBox.Show(customer.Name);
}
}
This can be solved by following the convention to prefix fields with an underscore:
这可以通过遵循惯例的前缀字段来解决:
private Customer _customer;
ASP.NET Page Life cycle:
public partial class Issues_Edit : System.Web.UI.Page
{
protected TestIssue myIssue;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Only called on first load, not when button clicked
myIssue = new TestIssue();
}
}
protected void SaveButton_Click(object sender, EventArgs e)
{
myIssue.Entry = "NullReferenceException here!";
}
}
ASP.NET Session Values
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
ASP.NET MVC empty view models
If the exception occurs when referencing a property of @Model
in an ASP.NET MVC view, you need to understand that the Model
gets set in your action method, when you return
a view. When you return an empty model (or model property) from your controller, the exception occurs when the views access it:
如果在ASP中引用@Model的属性时发生异常。NET MVC视图,您需要了解当您返回一个视图时,模型会在您的操作方法中被设置。当您从控制器返回空模型(或模型属性)时,当视图访问它时发生异常:
// Controller
public class Restaurant:Controller
{
public ActionResult Search()
{
return View(); // Forgot the provide a Model here.
}
}
// Razor view
@foreach (var restaurantSearch in Model.RestaurantSearch) // Throws.
{
}
<p>@Model.somePropertyName</p> <!-- Also throws -->
WPF Control Creation Order and Events
WPF controls are created during the call to InitializeComponent
in the order they appear in the visual tree. A NullReferenceException
will be raised in the case of early-created controls with event handlers, etc. , that fire during InitializeComponent
which reference late-created controls.
WPF控件是在调用InitializeComponent时创建的,它们是在可视树中出现的。在早期创建的控件和事件处理程序之间,将会出现一个NullReferenceException。
For example :
例如:
<Grid>
<!-- Combobox declared first -->
<ComboBox Name="comboBox1"
Margin="10"
SelectedIndex="0"
SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Content="Item 1" />
<ComboBoxItem Content="Item 2" />
<ComboBoxItem Content="Item 3" />
</ComboBox>
<!-- Label declared later -->
<Label Name="label1"
Content="Label"
Margin="10" />
</Grid>
Here comboBox1
is created before label1
. If comboBox1_SelectionChanged
attempts to reference `label1, it will not yet have been created.
在label1之前创建了comboBox1。如果comboBox1_SelectionChanged尝试引用“label1,它将不会被创建”。
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Changing the order of the declarations in the XAML (i.e., listing label1
before comboBox1
, ignoring issues of design philosophy, would at least resolve the NullReferenceException
here.
更改XAML中声明的顺序(即:在comboBox1之前列出label1,忽略了设计哲学的问题,至少可以解决这里的NullReferenceException。
Cast with as
var myThing = someObject as Thing;
This doesn't throw an InvalidCastException but returns a null
when the cast fails (and when someObject is itself null). So be aware of that.
这不会抛出InvalidCastException,但是当强制转换失败时返回一个null(当某个对象本身为空时)。所以要意识到这点。
LINQ FirstOrDefault() and SingleOrDefault()
The plain versions First()
and Single()
throw exceptions when there is nothing. The "OrDefault" versions return null in that case. So be aware of that.
普通版本第一个()和单个()抛出异常时,什么都没有。在这种情况下,“OrDefault”版本返回null。所以要意识到这点。
foreach
foreach
throws when you try to iterate null collection. Usually caused by unexpected null
result from methods that return collections.
在尝试迭代空集合时,foreach抛出。通常由返回集合的方法的意外空结果导致。
List<int> list = null;
foreach(var v in list) { } // exception
More realistic example - select nodes from XML document. Will throw if nodes are not found but initial debugging shows that all properties valid:
更现实的例子——从XML文档中选择节点。如果未找到节点,则会抛出,但初始调试显示所有属性都是有效的:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
Ways to Avoid
Explicitly check for null
and ignore null values.
If you expect the reference sometimes to be null, you can check for it being null
before accessing instance members:
如果您期望引用有时为null,那么您可以在访问实例成员之前检查它是否为null:
void PrintName(Person p) {
if (p != null) {
Console.WriteLine(p.Name);
}
}
Explicitly check for null
and provide a default value.
Methods call you expect to return an instance can return null
, for example when the object being sought cannot be found. You can choose to return a default value when this is the case:
方法调用您期望返回一个实例可以返回null,例如,当正在寻找的对象无法被找到时。当情况是这样时,您可以选择返回一个默认值:
string GetCategory(Book b) {
if (b == null)
return "Unknown";
return b.Category;
}
Explicitly check for null
from method calls and throw a custom exception.
You can also throw a custom exception, only to catch it in the calling code:
您还可以抛出一个定制的异常,只在调用代码中捕获它:
string GetCategory(string bookTitle) {
var book = library.FindBook(bookTitle); // This may return null
if (book == null)
throw new BookNotFoundException(bookTitle); // Your custom exception
return book.Category;
}
Use Debug.Assert
if a value should never be null
, to catch the problem earlier than the exception occurs.
When you know during development that a method maybe can, but never should return null
, you can use Debug.Assert()
to break as soon as possible when it does occur:
当您在开发过程中知道一个方法可能可以,但是永远不应该返回null时,您可以使用Debug.Assert()在发生时尽快中断:
string GetTitle(int knownBookID) {
// You know this should never return null.
var book = library.GetBook(knownBookID);
// Exception will occur on the next line instead of at the end of this method.
Debug.Assert(book != null, "Library didn't return a book for known book ID.");
// Some other code
return book.Title; // Will never throw NullReferenceException in Debug mode.
}
Though this check will not end up in your release build, causing it to throw the NullReferenceException
again when book == null
at runtime in release mode.
虽然此检查不会在您的发布版本中结束,但是在运行时,当book == null时,它会再次抛出NullReferenceException。
Use GetValueOrDefault()
for nullable value types to provide a default value when they are null
.
DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.
appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default
Use the null coalescing operator: ??
[C#] or If()
[VB].
The shorthand to providing a default value when a null
is encountered:
当遇到null时,提供默认值的简写如下:
IService CreateService(ILogger log, Int32? frobPowerLevel)
{
var serviceImpl = new MyService(log ?? NullLog.Instance);
// Note that the above "GetValueOrDefault()" can also be rewritten to use
// the coalesce operator:
serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}
Use the null condition operator: ?.
(available in C# 6 and VB.NET 14):
This is also sometimes called the safe navigation or Elvis (after its shape) operator. If the expression on the left side of the operator is null, then the right side will not be evaluated, and null is returned instead. That means cases like this:
这有时也被称为安全导航或猫王(在它的形状之后)。如果操作符左侧的表达式为null,那么右侧将不会被计算,反之则返回null。这意味着这样的情况:
var title = person.Title.ToUpper();
If the person does not have a title, this will throw an exception because it is trying to call ToUpper
on a property with a null value.
如果这个人没有标题,这将抛出一个异常,因为它试图在一个具有空值的属性上调用ToUpper。
In C# 5 and below, this can be guarded with:
在c# 5和下面,可以使用以下方法进行保护:
var title = person.Title == null ? null : person.Title.ToUpper();
Now the title variable will be null instead of throwing an exception. C# 6 introduces a shorter syntax for this:
现在title变量将为空,而不是抛出异常。c# 6引入了一个更简短的语法:
var title = person.Title?.ToUpper();
This will result in the title variable being null
, and the call to ToUpper
is not made if person.Title
is null
.
这将导致title变量为空,而对ToUpper的调用不是由person生成的。标题为空。
Of course, you still have to check title
for null or use the null condition operator together with the null coalescing operator (??
) to supply a default value:
当然,您仍然需要检查title是否为null,或者使用null条件操作符和null合并操作符(??)来提供默认值:
// regular null check
int titleLength = 0;
if (title != null)
titleLength = title.Length; // If title is null, this would throw NullReferenceException
// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;
#2
259
NullReference Exception — Visual Basic
The NullReference Exception
for Visual Basic is no different from the one in C#. After all, they are both reporting the same exception defined in the .NET Framework which they both use. Causes unique to Visual Basic are rare (perhaps only one).
Visual Basic的NullReference异常与c#中没有任何不同。毕竟,它们都报告了在. net框架中定义的相同的异常。独特的视觉基础是罕见的(也许只有一个)。
This answer will use Visual Basic terms, syntax, and context. The examples used come from a large number of past Stack Overflow questions. This is to maximize relevance by using the kinds of situations often seen in posts. A bit more explanation is also provided for those who might need it. An example similar to yours is very likely listed here.
这个答案将使用Visual Basic术语、语法和上下文。所使用的示例来自大量过去的堆栈溢出问题。这是通过在文章中经常看到的情况来最大化相关性。还为可能需要的人提供了更多的解释。类似于您的示例很可能在这里列出。
Note:
注意:
- This is concept-based: there is no code for you to paste into your project. It is intended to help you understand what causes a
NullReferenceException
(NRE), how to find it, how to fix it, and how to avoid it. An NRE can be caused many ways so this is unlikely to be your sole encounter. - 这是基于概念的:没有代码可以粘贴到您的项目中。它的目的是帮助您了解什么导致了NullReferenceException (NRE),如何找到它,如何修复它,以及如何避免它。一个NRE可以通过多种方式产生,所以这不太可能是你唯一的遭遇。
- The examples (from Stack Overflow posts) do not always show the best way to do something in the first place.
- 示例(从堆栈溢出的帖子)并不总是显示最好的方法来做一些事情。
- Typically, the simplest remedy is used.
- 通常,使用最简单的补救方法。
Basic Meaning
The message "Object not set to an instance of Object" means you are trying to use an object which has not been initialized. This boils down to one of these:
消息“对象未设置为对象实例”意味着您正在尝试使用尚未初始化的对象。这可以归结为一个问题:
- Your code declared an object variable, but it did not initialize it (create an instance or 'instantiate' it)
- 您的代码声明了一个对象变量,但是它没有初始化它(创建一个实例或者“实例化”它)
- Something which your code assumed would initialize an object, did not
- 你的代码假设会初始化一个对象,但没有。
- Possibly, other code prematurely invalidated an object still in use
- 可能,其他代码过早地使一个仍在使用的对象失效。
Finding The Cause
Since the problem is an object reference which is Nothing
, the answer is to examine them to find out which one. Then determine why it is not initialized. Hold the mouse over the various variables and Visual Studio (VS) will show their values - the culprit will be Nothing
.
由于这个问题是一个对象引用,它什么都不是,所以答案是检查它们以找出哪一个。然后确定它没有初始化的原因。把鼠标放在不同的变量上,Visual Studio (VS)将显示它们的值——罪魁祸首是什么都不是。
You should also remove any Try/Catch blocks from the relevant code, especially ones where there is nothing in the Catch block. This will cause your code to crash when it tries to use an object which is Nothing
. This is what you want because it will identify the exact location of the problem, and allow you to identify the object causing it.
您还应该从相关代码中删除任何Try/Catch块,特别是在Catch块中没有内容的地方。这将导致您的代码在试图使用一个没有任何内容的对象时崩溃。这是您想要的,因为它将识别问题的确切位置,并允许您识别导致它的对象。
A MsgBox
in the Catch which displays Error while...
will be of little help. This method also leads to very bad Stack Overflow questions, because you can't describe the actual exception, the object involved or even the line of code where it happens.
在Catch中显示错误的MsgBox。会有一点帮助。这种方法还会导致非常糟糕的堆栈溢出问题,因为您无法描述实际的异常、所涉及的对象,甚至无法描述它所发生的代码行。
You can also use the Locals Window
(Debug -> Windows -> Locals) to examine your objects.
您还可以使用local窗口(Debug ->窗口->本地)来检查对象。
Once you know what and where the problem is, it is usually fairly easy to fix and faster than posting a new question.
一旦你知道了问题所在,解决问题的方法往往比发布一个新问题要容易得多。
See also:
参见:
- Breakpoints
- 断点
- MSDN: How to: Use the Try/Catch Block to Catch Exceptions
- MSDN:如何:使用Try/Catch块捕获异常。
- MSDN: Best Practices for Exceptions
- MSDN:例外的最佳实践。
Examples and Remedies
Class Objects / Creating an Instance
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
The problem is that Dim
does not create a CashRegister object; it only declares a variable named reg
of that Type. Declaring an object variable and creating an instance are two different things.
问题是Dim不创建现金注册对象;它只声明一个名为reg的变量。声明一个对象变量并创建一个实例是两个不同的事情。
Remedy
补救措施
The New
operator can often be used to create the instance when you declare it:
当您声明该实例时,通常可以使用新的操作符来创建实例:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
When it is only appropriate to create the instance later:
当它只适合于稍后创建实例时:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Note: Do not use Dim
again in a procedure, including the constructor (Sub New
):
注意:在过程中不要再次使用Dim,包括构造函数(Sub - New):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
This will create a local variable, reg
, which exists only in that context (sub). The reg
variable with module level Scope
which you will use everywhere else remains Nothing
.
这将创建一个局部变量reg,它只存在于该上下文(sub)中。您将在其他地方使用的模块级范围的reg变量仍然没有。
Missing the
New
operator is the #1 cause ofNullReference Exceptions
seen in the Stack Overflow questions reviewed.缺少新操作符是在堆栈溢出问题中看到的NullReference异常的#1原因。
Visual Basic tries to make the process clear repeatedly using
New
: Using theNew
Operator creates a new object and callsSub New
-- the constructor -- where your object can perform any other initialization.Visual Basic试图用新方法使过程变得清晰:使用新操作符创建一个新对象,并调用subnew——构造函数——在这里,对象可以执行任何其他初始化。
To be clear, Dim
(or Private
) only declares a variable and its Type
. The Scope of the variable - whether it exists for the entire module/class or is local to a procedure - is determined by where it is declared. Private | Friend | Public
defines the access level, not Scope.
要清楚,Dim(或私有)只声明一个变量及其类型。变量的范围——是否存在于整个模块/类或者是本地的程序——取决于声明的位置。Private | Friend | Public定义访问级别,而不是范围。
For more information, see:
有关更多信息,请参见:
- New Operator
- 新的操作符
- Scope in Visual Basic
- 在Visual Basic范围
- Access Levels in Visual Basic
- 在Visual Basic中访问级别。
- Value Types and Reference Types
- 值类型和引用类型。
Arrays
Arrays must also be instantiated:
还必须实例化数组:
Private arr as String()
This array has only been declared, not created. There are several ways to initialize an array:
这个数组只被声明,而不是创建。有几种方法来初始化一个数组:
Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}
' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}
Note: Beginning with VS 2010, when initializing a local array using a literal and Option Infer
, the As <Type>
and New
elements are optional:
注意:从VS 2010开始,当使用文字和选项来初始化本地数组时,As
Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}
The data Type and array size are inferred from the data being assigned. Class/Module level declarations still require As <Type>
with Option Strict
:
数据类型和数组大小是根据分配的数据推断出来的。类/模块级声明仍然需要
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Example: Array of class objects
示例:类对象数组。
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
The array has been created, but the Foo
objects in it have not.
数组已经创建,但是Foo对象没有。
Remedy
补救措施
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Using a List(Of T)
will make it quite difficult to have an element without a valid object:
使用一个列表(T)将使一个没有有效对象的元素变得非常困难:
Dim FooList As New List(Of Foo) ' List created, but it is empty
Dim f As Foo ' Temporary variable for the loop
For i As Integer = 0 To 5
f = New Foo() ' Foo instance created
f.Bar = i * 10
FooList.Add(f) ' Foo object added to list
Next
For more information, see:
有关更多信息,请参见:
- Option Infer Statement
- 选项推断声明
- Scope in Visual Basic
- 在Visual Basic范围
- Arrays in Visual Basic
- Visual Basic中的数组
Lists and Collections
.NET collections (of which there are many varieties - Lists, Dictionary, etc.) must also be instantiated or created.
. net集合(其中有许多种类——列表、字典等)也必须被实例化或创建。
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
You get the same exception for the same reason - myList
was only declared, but no instance created. The remedy is the same:
同样的原因也会得到相同的异常——myList只声明,但没有创建实例。补救方法是一样的:
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
A common oversight is a class which uses a collection Type
:
常见的疏忽是使用集合类型的类:
Public Class Foo
Private barList As List(Of Bar)
Friend Function BarCount As Integer
Return barList.Count
End Function
Friend Sub AddItem(newBar As Bar)
If barList.Contains(newBar) = False Then
barList.Add(newBar)
End If
End Function
Either procedure will result in an NRE, because barList
is only declared, not instantiated. Creating an instance of Foo
will not also create an instance of the internal barList
. It may have been the intent to do this in the constructor:
任何一个过程都将导致一个NRE,因为barList只被声明,而不是实例化。创建一个Foo实例也不会创建内部barList的实例。它可能是在构造函数中这样做的目的:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
As before, this is incorrect:
如前所述,这是不正确的:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
For more information, see List(Of T)
Class.
有关更多信息,请参见列表(T)类。
Data Provider Objects
Working with databases presents many opportunities for a NullReference because there can be many objects (Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) in use at once. Note: It does not matter which data provider you are using -- MySQL, SQL Server, OleDB, etc. -- the concepts are the same.
使用数据库提供了许多机会NullReference因为可以有许多对象(命令、连接、事务、数据集,数据表,我们应该....)使用。注意:您使用的数据提供者(MySQL、SQL Server、OleDB等)并不重要,概念是相同的。
Example 1
示例1
Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer
con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()
MaxRows = ds.Tables("foobar").Rows.Count ' Error
As before, the ds
Dataset object was declared, but an instance was never created. The DataAdapter
will fill an existing DataSet
, not create one. In this case, since ds
is a local variable, the IDE warns you that this might happen:
与前面一样,声明了ds数据集对象,但从未创建实例。DataAdapter将填充现有的数据集,而不是创建一个。在本例中,由于ds是一个局部变量,IDE警告您这可能会发生:
When declared as a module/class level variable, as appears to be the case with con
, the compiler can't know if the object was created by an upstream procedure. Do not ignore warnings.
当被声明为模块/类级别变量时,似乎是con的情况,编译器不知道该对象是由上游过程创建的。不要忽视警告。
Remedy
补救措施
Dim ds As New DataSet
Example 2
示例2
ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")
txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)
A typo is a problem here: Employees
vs Employee
. There was no DataTable
named "Employee" created, so a NullReferenceException
results trying to access it. Another potential problem is assuming there will be Items
which may not be so when the SQL includes a WHERE clause.
在这里输入错误是一个问题:雇员和雇员。没有创建名为“Employee”的DataTable,因此试图访问它的NullReferenceException结果。另一个潜在的问题是,假设在SQL中包含WHERE子句时可能不会出现某些项。
Remedy
补救措施
Since this uses one table, using Tables(0)
will avoid spelling errors. Examining Rows.Count
can also help:
由于使用了一个表,所以使用表(0)可以避免拼写错误。检查行。数也可以帮助:
If ds.Tables(0).Rows.Count > 0 Then
txtID.Text = ds.Tables(0).Rows(0).Item(1)
txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If
Fill
is a function returning the number of Rows
affected which can also be tested:
Fill是返回受影响的行数的函数,也可以进行测试:
If da.Fill(ds, "Employees") > 0 Then...
Example 3
示例3
Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)
If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then
The DataAdapter
will provide TableNames
as shown in the previous example, but it does not parse names from the SQL or database table. As a result, ds.Tables("TICKET_RESERVATION")
references a non-existent table.
DataAdapter将按照前面的示例提供TableNames,但它不解析SQL或数据库表中的名称。因此,表(“TICKET_RESERVATION”)引用了一个不存在的表。
The Remedy is the same, reference the table by index:
补救方法是相同的,参照表的索引:
If ds.Tables(0).Rows.Count > 0 Then
See also DataTable Class.
参见DataTable类。
Object Paths / Nested
If myFoo.Bar.Items IsNot Nothing Then
...
The code is only testing Items
while both myFoo
and Bar
may also be Nothing. The remedy is to test the entire chain or path of objects one at a time:
代码只是测试项目,而myFoo和Bar也可能什么都不是。补救方法是一次测试一个对象的整个链或路径:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
is important. Subsequent tests will not be performed once the first False
condition is encountered. This allows the code to safely 'drill' into the object(s) one 'level' at a time, evaluating myFoo.Bar
only after (and if) myFoo
is determined to be valid. Object chains or paths can get quite long when coding complex objects:
需要说明是非常重要的。在遇到第一个错误条件后,将不会执行后续测试。这使得代码可以一次安全地“钻”到对象的一个“级别”,评估myFoo。只有在(并且如果)myFoo被确定为有效之后,Bar才会生效。当编码复杂对象时,对象链或路径会变得很长:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
It is not possible to reference anything 'downstream' of a null
object. This also applies to controls:
不可能引用空对象的任何“下游”。这也适用于控制:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Here, myWebBrowser
or Document
could be Nothing or the formfld1
element may not exist.
在这里,myWebBrowser或Document可能不存在,或者formfld1元素可能不存在。
UI Controls
Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
& "FROM Invoice where invoice_no = '" & _
Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
Me.expiry.Text & "'", con)
Among other things, this code does not anticipate that the user may not have selected something in one or more UI controls. ListBox1.SelectedItem
may well be Nothing
, so ListBox1.SelectedItem.ToString
will result in an NRE.
除其他外,此代码没有预料到用户可能没有在一个或多个UI控件中选择某些内容。ListBox1。SelectedItem很可能什么都不是,所以ListBox1.SelectedItem。ToString将导致NRE。
Remedy
补救措施
Validate data before using it (also use Option Strict
and SQL parameters):
在使用前验证数据(也使用选项严格和SQL参数):
Dim expiry As DateTime ' for text date validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
(ListBox1.SelectedItems.Count > 0) AndAlso
(ComboBox2.SelectedItems.Count > 0) AndAlso
(DateTime.TryParse(expiry.Text, expiry) Then
'... do stuff
Else
MessageBox.Show(...error message...)
End If
Alternatively, you can use (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
或者,也可以使用(ComboBox5)。设置SelectedItem不是什么)以及……
Visual Basic Forms
Public Class Form1
Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
Controls("TextBox2"), Controls("TextBox3"), _
Controls("TextBox4"), Controls("TextBox5"), _
Controls("TextBox6")}
' same thing in a different format:
Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}
' Immediate NRE:
Private somevar As String = Me.Controls("TextBox1").Text
This is a fairly common way to get an NRE. In C#, depending on how it is coded, the IDE will report that Controls
does not exist in the current context, or "cannot reference non-static member". So, to some extent, this is a VB-only situation. It is also complex because it can result in a failure cascade.
这是获得NRE的一个相当普遍的方法。在c#中,根据它的编码方式,IDE将报告当前上下文中不存在控件,或者“不能引用非静态成员”。因此,在某种程度上,这是一个vb的情况。它也很复杂,因为它会导致失败级联。
The arrays and collections cannot be initialized this way. This initialization code will run before the constructor creates the Form
or the Controls
. As a result:
数组和集合不能以这种方式初始化。此初始化代码将在构造函数创建窗体或控件之前运行。结果:
- Lists and Collection will simply be empty
- 列表和集合将是空的。
- The Array will contain five elements of Nothing
- 该数组将包含5个元素。
- The
somevar
assignment will result in an immediate NRE because Nothing doesn't have a.Text
property - somevar赋值将导致立即的NRE,因为没有任何东西没有.Text属性。
Referencing array elements later will result in an NRE. If you do this in Form_Load
, due to an odd bug, the IDE may not report the exception when it happens. The exception will pop up later when your code tries to use the array. This "silent exception" is detailed in this post. For our purposes, the key is that when something catastrophic happens while creating a form (Sub New
or Form Load
event), exceptions may go unreported, the code exits the procedure and just displays the form.
稍后引用数组元素将导致NRE。如果在Form_Load中这样做,由于一个奇怪的错误,IDE可能不会在发生异常时报告异常。当代码试图使用数组时,异常会出现。这个“沉默的例外”在这个帖子里是详细的。对于我们的目的,关键是当在创建表单时发生了一些灾难性的事情(新的或表单加载事件),异常可能会被忽略,代码会退出过程并显示表单。
Since no other code in your Sub New
or Form Load
event will run after the NRE, a great many other things can be left uninitialized.
因为在您的子新或表单加载事件中没有其他代码会在NRE之后运行,所以很多其他的东西都可以不被初始化。
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Note this applies to any and all control and component references making these illegal where they are:
请注意,这适用于任何和所有控制和组件引用,使它们成为非法的地方:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Partial Remedy
部分解决
It is curious that VB does not provide a warning, but the remedy is to declare the containers at the form level, but initialize them in form load event handler when the controls do exist. This can be done in Sub New
as long as your code is after the InitializeComponent
call:
奇怪的是,VB没有提供警告,但是补救方法是在表单级别声明容器,但是当控件存在时,将它们初始化为form load事件处理程序。只要您的代码是在InitializeComponent调用之后,这就可以在Sub - New中完成:
' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String
' Form Load, Form Shown or Sub New:
'
' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...)
studentName = TextBox32.Text ' For simple control references
The array code may not be out of the woods yet. Any controls which are in a container control (like a GroupBox
or Panel
) will not be found in Me.Controls
; they will be in the Controls collection of that Panel or GroupBox. Nor will a control be returned when the control name is misspelled ("TeStBox2"
). In such cases, Nothing
will again be stored in those array elements and an NRE will result when you attempt to reference it.
数组代码可能还没有脱离险境。任何在容器控件中(如GroupBox或Panel)的控件都不会在me .控件中找到;它们将在该面板或GroupBox的控件集合中。当控件名称拼写错误(“TeStBox2”)时,控件也不会返回。在这种情况下,当您尝试引用它时,将不会再次存储这些数组元素和NRE。
These should be easy to find now that you know what you are looking for:
这些应该很容易找到,因为你知道你在寻找什么:
"Button2" resides on a Panel
“Button2”位于一个面板上。
Remedy
补救措施
Rather than indirect references by name using the form's Controls
collection, use the control reference:
使用控件引用,而不是使用表单控件集合的名称间接引用:
' Declaration
Private NameBoxes As TextBox()
' Initialization - simple and easy to read, hard to botch:
NameBoxes = New TextBox() {TextBox1, TextBox2, ...)
' Initialize a List
NamesList = New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})
' or
NamesList = New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})
Function Returning Nothing
Private bars As New List(Of Bars) ' Declared and created
Public Function BarList() As List(Of Bars)
bars.Clear
If someCondition Then
For n As Integer = 0 to someValue
bars.Add(GetBar(n))
Next n
Else
Exit Function
End If
Return bars
End Function
This is a case where the IDE will warn you that 'not all paths return a value and a NullReferenceException
may result'. You can suppress the warning, by replacing Exit Function
with Return Nothing
, but that does not solve the problem. Anything which tries to use the return when someCondition = False
will result in an NRE:
在这种情况下,IDE会警告您“不是所有路径返回一个值,而NullReferenceException可能会导致”。您可以通过替换Exit函数来抑制警告,但是这并不能解决问题。任何试图使用返回时,当someCondition = False时,将导致NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Remedy
补救措施
Replace Exit Function
in the function with Return bList
. Returning an empty List
is not the same as returning Nothing
. If there is a chance that a returned object can be Nothing
, test before using it:
用Return bList替换函数中的Exit函数。返回空列表不等同于返回空列表。如果返回的对象不可能是空的,则在使用它之前进行测试:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Poorly Implemented Try/Catch
A badly implemented Try/Catch can hide where the problem is and result in new ones:
一个被严重执行的Try/Catch可以隐藏问题所在,并导致新的问题:
Dim dr As SqlDataReader
Try
Dim lnk As LinkButton = TryCast(sender, LinkButton)
Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
ViewState("username") = eid
sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
Pager, mailaddress, from employees1 where username='" & eid & "'"
If connection.State <> ConnectionState.Open Then
connection.Open()
End If
command = New SqlCommand(sqlQry, connection)
'More code fooing and barring
dr = command.ExecuteReader()
If dr.Read() Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))
...
End If
mpe.Show()
Catch
Finally
command.Dispose()
dr.Close() ' <-- NRE
connection.Close()
End Try
This is a case of an object not being created as expected, but also demonstrates the counter usefulness of an empty Catch
.
这是一个不像预期的那样创建对象的情况,但也演示了空捕获的计数器有用性。
There is an extra comma in the SQL (after 'mailaddress') which results in an exception at .ExecuteReader
. After the Catch
does nothing, Finally
tries to perform clean up, but since you cannot Close
a null DataReader
object, a brand new NullReferenceException
results.
SQL中有一个额外的逗号(在“mailaddress”之后),这将导致. executereader异常。捕获后什么都不做,最后尝试执行清理,但是由于您不能关闭空DataReader对象,一个全新的NullReferenceException结果。
An empty Catch
block is the devil's playground. This OP was baffled why he was getting an NRE in the Finally
block. In other situations, an empty Catch
may result in something else much further downstream going haywire and cause you to spend time looking at the wrong things in the wrong place for the problem. (The "silent exception" described above provides the same entertainment value.)
一个空的挡块是魔鬼的游乐场。这个OP被搞糊涂了,为什么他在最后一个街区得到了一个NRE。在其他情况下,一个空的捕获可能会导致其他一些更下游的事情失控,导致你花时间在错误的地方查看错误的事情。(上面描述的“静默例外”提供了相同的娱乐价值。)
Remedy
补救措施
Don't use empty Try/Catch blocks - let the code crash so you can a) identify the cause b) identify the location and c) apply a proper remedy. Try/Catch blocks are not intended to hide exceptions from the person uniquely qualified to fix them - the developer.
不要使用空的Try/Catch块——让代码崩溃,这样你就可以a)识别原因b)确定位置和c)应用适当的补救方法。Try/Catch块的目的不是为了隐藏特定于修复它们的人的异常——开发人员。
DBNull is not the same as Nothing
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
The IsDBNull
function is used to test if a value equals System.DBNull
: From MSDN:
IsDBNull函数用于测试一个值是否等于系统。从MSDN DBNull::
The System.DBNull value indicates that the Object represents missing or non-existent data. DBNull is not the same as Nothing, which indicates that a variable has not yet been initialized.
这个系统。DBNull值表示对象表示丢失或不存在的数据。DBNull不等同于Nothing,这表明变量还没有初始化。
Remedy
补救措施
If row.Cells(0) IsNot Nothing Then ...
As before, you can test for Nothing, then for a specific value:
如前所述,您可以对任何东西进行测试,然后对特定的值进行测试:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Example 2
示例2
Dim getFoo = (From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
If Not IsDBNull(getFoo) Then
If IsDBNull(getFoo.user_id) Then
txtFirst.Text = getFoo.first_name
Else
...
FirstOrDefault
returns the first item or the default value, which is Nothing
for reference types and never DBNull
:
FirstOrDefault返回第一个项或默认值,这对于引用类型来说是没有意义的,也不会返回DBNull:
If getFoo IsNot Nothing Then...
Controls
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
If a CheckBox
with chkName
can't be found (or exists in a GroupBox
), then chk
will be Nothing and be attempting to reference any property will result in an exception.
如果无法找到带有chkName的复选框(或在GroupBox中存在),则chk将不存在,并试图引用任何属性将导致异常。
Remedy
补救措施
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
The DataGridView
The DGV has a few quirks seen periodically:
DGV有一些周期性的怪癖:
dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"
If dgvBooks
has AutoGenerateColumns = True
, it will create the columns, but it does not name them, so the above code fails when it references them by name.
如果dgvBooks具有AutoGenerateColumns = True,它将创建列,但它不命名它们,因此当它引用它们的名称时,上面的代码会失败。
Remedy
补救措施
Name the columns manually, or reference by index:
手动命名列,或通过索引引用:
dgvBooks.Columns(0).Visible = True
Example 2 — Beware of the NewRow
xlWorkSheet = xlWorkBook.Sheets("sheet1")
For i = 0 To myDGV.RowCount - 1
For j = 0 To myDGV.ColumnCount - 1
For k As Integer = 1 To myDGV.Columns.Count
xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
Next
Next
Next
When your DataGridView
has AllowUserToAddRows
as True
(the default), the Cells
in the blank/new row at the bottom will all contain Nothing
. Most attempts to use the contents (for example, ToString
) will result in an NRE.
当DataGridView允许usertoaddrows为True(默认值)时,位于底部的空/新行中的单元格将全部不包含任何内容。大多数尝试使用内容(例如,ToString)都会导致NRE。
Remedy
补救措施
Use a For/Each
loop and test the IsNewRow
property to determine if it is that last row. This works whether AllowUserToAddRows
is true or not:
使用For/Each循环并测试IsNewRow属性,以确定它是否是最后一行。无论AllowUserToAddRows是否为真,这都是可行的:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
If you do use a For n
loop, modify the row count or use Exit For
when IsNewRow
is true.
如果您确实使用For n循环,那么在IsNewRow为真时,修改行计数或使用Exit。
My.Settings (StringCollection)
Under certain circumstances, trying to use an item from My.Settings
which is a StringCollection
can result in a NullReference the first time you use it. The solution is the same, but not as obvious. Consider:
在某些情况下,试图使用我的物品。设置是一个StringCollection,可以在第一次使用它时产生NullReference。解决方案是一样的,但不是很明显。考虑:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Since VB is managing Settings for you, it is reasonable to expect it to initialize the collection. It will, but only if you have previously added an initial entry to the collection (in the Settings editor). Since the collection is (apparently) initialized when an item is added, it remains Nothing
when there are no items in the Settings editor to add.
由于VB是为您管理设置,因此期望它初始化集合是合理的。它将会,但前提是您之前添加了一个初始条目到集合(在设置编辑器中)。因为在添加一个项时,集合(显然)是初始化的,所以在设置编辑器中没有添加任何项时,它仍然是空的。
Remedy
补救措施
Initialize the settings collection in the form's Load
event handler, if/when needed:
如果需要,在表单的加载事件处理程序中初始化设置集合:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Typically, the Settings
collection will only need to be initialized the first time the application runs. An alternate remedy is to add an initial value to your collection in Project -> Settings | FooBars, save the project, then remove the fake value.
通常,设置集合只需要在应用程序第一次运行时初始化。另一种补救方法是在项目->设置| FooBars中添加一个初始值,保存项目,然后删除假值。
Key Points
You probably forgot the New
operator.
你可能忘记了新的接线员。
or
或
Something you assumed would perform flawlessly to return an initialized object to your code, did not.
您假定的某些东西将完美地执行,以返回初始化的对象到您的代码,但没有。
Don't ignore compiler warnings (ever) and use Option Strict On
(always).
不要忽略编译器警告(永远),并严格使用选项(总是)。
MSDN NullReference例外
#3
208
Another scenario is when you cast a null object into a value type. For example, the code below:
另一种情况是将null对象转换为值类型。例如,下面的代码:
object o = null;
DateTime d = (DateTime)o;
It will throw a NullReferenceException
on the cast. It seems quite obvious in the above sample, but this can happen in more "late-binding" intricate scenarios where the null object has been returned from some code you don't own, and the cast is for example generated by some automatic system.
它将在cast上抛出一个NullReferenceException。在上面的示例中,这似乎很明显,但是这可能发生在更“后期绑定”的复杂场景中,在这里,null对象从一些您不拥有的代码中返回,而cast是由一些自动系统生成的。
One example of this is this simple ASP.NET binding fragment with the Calendar control:
一个例子就是这个简单的ASP。与日历控件的网络绑定片段:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Here, SelectedDate
is in fact a property - of DateTime
type - of the Calendar
Web Control type, and the binding could perfectly return something null. The implicit ASP.NET Generator will create a piece of code that will be equivalent to the cast code above. And this will raise a NullReferenceException
that is quite difficult to spot, because it lies in ASP.NET generated code which compiles fine...
这里,SelectedDate实际上是日历Web控件类型的DateTime类型的属性,绑定可以完美地返回null。隐式的ASP。NET生成器将创建一个与上面的cast代码等价的代码。这将会引发一个NullReferenceException异常,因为它位于ASP中。NET生成的代码,编译好的…
#4
139
It means that the variable in question is pointed at nothing. I could generate this like so:
这意味着问题中的变量没有指向任何东西。我可以这样生成:
SqlConnection connection = null;
connection.Open();
That will throw the error because while I've declared the variable "connection
", it's not pointed to anything. When I try to call the member "Open
", there's no reference for it to resolve, and it will throw the error.
这将抛出错误,因为当我声明变量“connection”时,它并没有指向任何东西。当我尝试调用成员“Open”时,没有对它进行解析的引用,它会抛出错误。
To avoid this error:
为了避免这个错误:
- Always initialize your objects before you try to do anything with them.
- 在尝试使用它们之前,总是先初始化对象。
- If you're not sure whether the object is null, check it with
object == null
. - 如果您不确定该对象是否为空,请用object == null检查它。
JetBrains' Resharper tool will identify every place in your code that has the possibility of a null reference error, allowing you to put in a null check. This error is the number one source of bugs, IMHO.
JetBrains的Resharper工具将识别代码中所有可能出现空引用错误的地方,允许您进行空检查。这个错误是bug的头号来源,IMHO。
#5
131
It means your code used an object reference variable that was set to null (i.e. it did not reference an actual object instance).
这意味着您的代码使用的对象引用变量被设置为null(即它没有引用实际的对象实例)。
To prevent the error, objects that could be null should be tested for null before being used.
为了防止错误,可以在使用null之前对可能为null的对象进行测试。
if (myvar != null)
{
// Go ahead and use myvar
myvar.property = ...
}
else
{
// Whoops! myvar is null and cannot be used without first
// assigning it to an instance reference
// Attempting to use myvar here will result in NullReferenceException
}
#6
86
Be aware that regardless of the scenario, the cause is always the same in .NET:
请注意,无论场景如何,在。net中,原因总是相同的:
You are trying to use a reference variable whose value is
Nothing
/null
. When the value isNothing
/null
for the reference variable, that means it is not actually holding a reference to an instance of any object that exists on the heap.您正在尝试使用一个值为零的引用变量。当引用变量的值为零/null时,这意味着它实际上并没有对存在于堆上的任何对象的实例进行引用。
You either never assigned something to the variable, never created an instance of the value assigned to the variable, or you set the variable equal to
Nothing
/null
manually, or you called a function that set the variable toNothing
/null
for you.您要么从来没有给变量赋值,也没有创建赋给变量的值的实例,或者您将变量设置为空值/null,或者您调用了一个函数,该函数将变量设置为Nothing/null。
#7
73
An example of this exception being thrown is: When you are trying to check something, that is null.
抛出这个异常的一个例子是:当您试图检查某个东西时,它是空的。
For example:
例如:
string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)
if (testString.Length == 0) // Throws a nullreferenceexception
{
//Do something
}
The .NET runtime will throw a NullReferenceException when you attempt to perform an action on something which hasn't been instantiated i.e. the code above.
当您试图对未实例化的对象执行操作时,. net运行时将抛出一个NullReferenceException,即上面的代码。
In comparison to an ArgumentNullException which is typically thrown as a defensive measure if a method expects that what is being passed to it is not null.
与通常作为防御措施抛出的ArgumentNullException相比,如果方法期望传递给它的值不是null。
More information is in C# NullReferenceException and Null Parameter.
更多信息在c# NullReferenceException和Null参数中。
#8
67
If you have not initialized a reference type, and you want to set or read one of its properties, it will throw a NullReferenceException.
如果没有初始化引用类型,并且希望设置或读取它的一个属性,它将抛出一个NullReferenceException。
Example:
例子:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
You can simply avoid this by checking if the variable is not null:
您可以通过检查变量是否为null来避免这一点:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
To fully understand why a NullReferenceException is thrown, it is important to know the difference between value types and reference types.
要完全理解为什么会抛出NullReferenceException,重要的是要知道值类型和引用类型之间的区别。
So, if you're dealing with value types, NullReferenceExceptions can not occur. Though you need to keep alert when dealing with reference types!
因此,如果您正在处理值类型,则不可能出现nullreferenceexception。虽然您需要在处理引用类型时保持警惕!
Only reference types, as the name is suggesting, can hold references or point literally to nothing (or 'null'). Whereas value types always contain a value.
只有引用类型,顾名思义,可以保存引用或指向任何东西(或“null”)。而值类型总是包含一个值。
Reference types (these ones must be checked):
引用类型(必须检查这些类型):
- dynamic
- 动态
- object
- 对象
- string
- 字符串
Value types (you can simply ignore these ones):
值类型(您可以忽略这些类型):
- Numeric types
- 数值类型
- Integral types
- 积分类型
- Floating-point types
- 浮点类型
- decimal
- 小数
- bool
- bool
- User defined structs
- 用户定义的结构体
#9
62
Another case where NullReferenceExceptions
can happen is the (incorrect) use of the as
operator:
nullreferenceexception可能发生的另一种情况是(不正确的)使用as操作符:
class Book {
public string Name { get; set; }
}
class Car { }
Car mycar = new Car();
Book mybook = mycar as Book; // Incompatible conversion --> mybook = null
Console.WriteLine(mybook.Name); // NullReferenceException
Here, Book
and Car
are incompatible types; a Car
cannot be converted/cast to a Book
. When this cast fails, as
returns null
. Using mybook
after this causes a NullReferenceException
.
在这里,书和车是不兼容的类型;汽车不能转换成一本书。当这个cast失败时,返回null。在此之后使用mybook将导致NullReferenceException。
In general, you should use a cast or as
, as follows:
一般来说,你应该使用一个cast或as,如下:
If you are expecting the type conversion to always succeed (ie. you know what the object should be ahead of time), then you should use a cast:
如果您期望类型转换总是成功的(ie)。你知道什么东西应该提前,然后你应该使用一个演员:
ComicBook cb = (ComicBook)specificBook;
If you are unsure of the type, but you want to try to use it as a specific type, then use as
:
如果您不确定该类型,但是您想尝试将其作为特定类型使用,然后使用as:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
#10
57
You are using the object that contains the null value reference. So it's giving a null exception. In the example the string value is null and when checking its length, the exception occurred.
您正在使用包含空值引用的对象。它给出了一个空异常。在示例中,字符串值为null,当检查其长度时,异常发生。
Example:
例子:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
The exception error is:
异常的错误是:
Unhandled Exception:
未处理的例外:
System.NullReferenceException: Object reference not set to an instance of an object. at Program.Main()
系统。NullReferenceException:对象引用没有设置为对象的实例。在Program.Main()
#11
45
Simon Mourier gave this example:
Simon Mourier给出了这个例子:
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
where an unboxing conversion (cast) from object
(or from one of the classes System.ValueType
or System.Enum
, or from an interface type) to a value type (other than Nullable<>
) in itself gives the NullReferenceException
.
从对象(或从一个类系统中)进行非装箱转换(cast)的地方。ValueType或系统。枚举(或从接口类型)到值类型(除了Nullable<>)本身提供了NullReferenceException。
In the other direction, a boxing conversion from a Nullable<>
which has HasValue
equal to false
to a reference type, can give a null
reference which can then later lead to a NullReferenceException
. The classic example is:
在另一个方向上,从一个可空的<>,它的值等于false到引用类型的一个装箱转换,可以给出一个空引用,然后可以导致一个NullReferenceException。典型的例子是:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Sometimes the boxing happens in another way. For example with this non-generic extension method:
有时,拳击会以另一种方式发生。例如,使用这种非通用的扩展方法:
public static void MyExtension(this object x)
{
x.ToString();
}
the following code will be problematic:
下面的代码会有问题:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
These cases arise because of the special rules the runtime uses when boxing Nullable<>
instances.
这些情况出现的原因是,运行时使用的特殊规则会在装箱时使用无效的<>实例。
#12
37
While what causes a NullReferenceExceptions and approaches to avoid/fix such an exception have been addressed in other answers, what many programmers haven't learned yet is how to independently debug such exceptions during development.
虽然导致nullreferenceexception的原因和避免/修复此类异常的方法已经在其他答案中得到解决,但是许多程序员还没有学会如何在开发过程中独立地调试这些异常。
In Visual Studio this is usually easy thanks to the Visual Studio Debugger.
在Visual Studio中,这通常要归功于Visual Studio调试器。
First, make sure that the correct error is going to be caught - see How do I allow breaking on 'System.NullReferenceException' in VS2010? Note1
首先,确保正确的错误将被捕获——看看我如何允许中断系统。在VS2010得到NullReferenceException’?注一
Then either Start with Debugging (F5) or Attach [the VS Debugger] to Running Process. On occasion it may be useful to use Debugger.Break
, which will prompt to launch the debugger.
然后,要么从调试(F5)开始,要么将[VS调试器]附加到运行进程。有时,使用调试器可能是有用的。中断,它将提示启动调试器。
Now, when the NullReferenceException is thrown (or unhandled) the debugger will stop (remember the rule set above?) on the line on which the exception occurred. Sometimes the error will be easy to spot.
现在,当抛出(或未处理)NullReferenceException时,调试器将停止(记住上面的规则集),而在该异常发生的行上。有时这个错误很容易被发现。
For instance, in the following line the only code that can cause the exception is if myString
evaluates to null. This can be verified by looking at the Watch Window or running expressions in the Immediate Window.
例如,在下面一行中,唯一可能导致异常的代码是如果myString计算为null。这可以通过查看表窗口或直接窗口中的运行表达式来验证。
var x = myString.Trim();
In more advanced cases, such as the following, you'll need to use one of the techniques above (Watch or Immediate Windows) to inspect the expressions to determine if str1
was null or if str2
was null.
在更高级的情况下,比如下面的例子,您需要使用上面的技术之一(观察或直接窗口)来检查表达式,以确定str1是否为null,或者str2是否为null。
var x = str1.Trim() + str2.Trim();
Once where the exception is throw has been located, it's usually trivial to reason backwards to find out where the null value was [incorrectly] introduced --
一旦抛出异常的位置,通常就会很容易地找出null值(错误地)引入的地方。
Take the time required to understand the cause of the exception. Inspect for null expressions. Inspect the previous expressions which could have resulted in such null expressions. Add breakpoints and step through the program as appropriate. Use the debugger.
花时间去了解异常的原因。检查空表达式。检查之前可能导致这种空表达式的表达式。在适当的时候添加断点和步骤。使用调试器。
1 If Break on Throws is too aggressive and the debugger stops on an NPE in the .NET or 3rd-party library, Break on User-Unhandled can be used to limit the exceptions caught. Additionally, VS2012 introduces Just My Code which I recommend enabling as well.
如果在. net或3rd-party库中,如果中断的攻击太过激烈,调试器停止在NPE上,则可以使用用户未处理的中断来限制捕获的异常。另外,VS2012只介绍了我建议启用的代码。
If you are debugging with Just My Code enabled, the behavior is slightly different. With Just My Code enabled, the debugger ignores first-chance common language runtime (CLR) exceptions that are thrown outside of My Code and do not pass through My Code
如果您正在调试仅启用了我的代码,则行为略有不同。在启用了我的代码之后,调试器将忽略在我的代码之外抛出的第一个常见语言运行时(CLR)异常,并且不通过我的代码。
#13
35
Adding a case when the class name for entity used in entity framework is same as class name for a web form code-behind file.
当实体框架中使用的实体的类名与web表单代码后文件的类名相同时,添加一个case。
Suppose you have a web form Contact.aspx whose codebehind class is Contact and you have an entity name Contact.
假设您有一个web表单联系人。它的codebehind类是Contact,并且您有一个实体名称Contact。
Then following code will throw a NullReferenceException when you call context.SaveChanges()
然后,当您调用context.SaveChanges()时,下面的代码将抛出一个NullReferenceException。
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
For the sake of completeness DataContext class
为了完整的DataContext类。
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
and Contact entity class. Sometimes entity classes are partial classes so that you can extend them in other files too.
和联系实体类。有时,实体类是部分类,因此您也可以将它们扩展到其他文件中。
public partial class Contact
{
public string Name {get; set;}
}
The error occurs when both the entity and codebehind class are in same namespace. To fix this, rename the entity class or the codebehind class for Contact.aspx.
当实体和codebehind类都在同一个名称空间中时,就会出现错误。要修复这个问题,将实体类重命名为Contact.aspx的代码后类。
Reason I am still not sure about the reason. But whenever any of the entity class will extend System.Web.UI.Page this error occurs.
原因我还是不太清楚。但无论何时,任何实体类都将扩展System.Web.UI。页面会发生此错误。
For discussion have a look at NullReferenceException in DbContext.saveChanges()
对于讨论,请查看DbContext.saveChanges()中的NullReferenceException
#14
34
Another general case where one might receive this exception involves mocking classes during unit testing. Regardless of the mocking framework being used, you must ensure that all appropriate levels of the class hierarchy are properly mocked. In particular, all properties of HttpContext
which are referenced by the code under test must be mocked.
另一个常见的情况是,在单元测试期间,可能会收到这个异常的模拟类。不管使用了什么mock框架,都必须确保正确地模拟了类层次结构的所有适当级别。特别是,在测试代码中引用的HttpContext的所有属性都必须被嘲笑。
See "NullReferenceException thrown when testing custom AuthorizationAttribute" for a somewhat verbose example.
参见“在测试自定义AuthorizationAttribute时抛出的NullReferenceException”,这是一个有点冗长的示例。
#15
33
I have a different perspective to answering this. This sort of answers "what else can I do to avoid it?"
我对此有不同的看法。这样的回答“我还能做些什么来避免它呢?”
When working across different layers, for example in an MVC application, a controller needs services to call business operations. In such scenarios Dependency Injection Container can be used to initialize the services to avoid the NullReferenceException. So that means you don't need to worry about checking for null and just call the services from the controller as though they will always to available (and initialized) as either a singleton or a prototype.
当跨不同的层工作时,例如在MVC应用程序中,控制器需要服务来调用业务操作。在这种情况下,可以使用依赖注入容器来初始化服务,以避免NullReferenceException。因此,这意味着您不必担心检查null值,只需从控制器调用服务,就像它们将始终可用(并初始化)作为单例或原型一样。
public class MyController
{
private ServiceA serviceA;
private ServiceB serviceB;
public MyController(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void MyMethod()
{
// We don't need to check null because the dependency injection container
// injects it, provided you took care of bootstrapping it.
var someObject = serviceA.DoThis();
}
}
#16
31
On the matter of "what should I do about it", there can be many answers.
关于“我该怎么做”的问题,可以有很多答案。
A more "formal" way of preventing such error conditions while developing is applying design by contract in your code. This means you need to set class invariants, and/or even function/method preconditions and postconditions on your system, while developing.
在开发过程中,一种更“正式”的方法来防止这样的错误情况,这是在代码中应用契约式设计。这意味着您需要在开发过程中设置类不变量,以及/或甚至函数/方法前置条件和后置条件。
In short, class invariants ensure that there will be some constraints in your class that will not get violated in normal use (and therefore, the class will not get in an inconsistent state). Preconditions mean that data given as input to a function/method must follow some constraints set and never violate them, and postconditions mean that a function/method output must follow the set constraints again without ever violating them. Contract conditions should never be violated during execution of a bug-free program, therefore design by contract is checked in practice in debug mode, while being disabled in releases, to maximize the developed system performance.
简而言之,类不变量确保在您的类中有一些约束不会在正常使用中被违背(因此,该类不会处于不一致的状态)。前提条件是,作为函数/方法输入的数据必须遵循一定的约束条件,且不可违背,而postconditions意味着函数/方法输出必须再次遵循设置约束,而不会违反它们。在没有bug的程序执行过程中,不应该违反合同条件,因此,在调试模式下,在调试模式下进行设计,同时在发布中禁用,以最大化开发系统的性能。
This way, you can avoid NullReferenceException
cases that are results of violation of the constraints set. For example, if you use an object property X
in a class and later try to invoke one of its methods and X
has a null value, then this will lead to NullReferenceException
:
通过这种方式,您可以避免NullReferenceException异常,这是对约束集的违反结果。
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
But if you set "property X must never have a null value" as method precondition, then you can prevent the scenario described before:
但是,如果您设置“属性X必须永远没有空值”作为方法前提条件,那么您可以防止前面描述的场景:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
For this cause, Code Contracts project exists for .NET applications.
对于这个原因,. net应用程序存在代码契约项目。
Alternatively, design by contract can be applied using assertions.
或者,可以使用断言来应用契约式设计。
UPDATE: It is worth mentioning that the term was coined by Bertrand Meyer in connection with his design of the Eiffel programming language.
更新:值得一提的是,这个词是由Bertrand Meyer和他设计的埃菲尔编程语言创造的。
#17
30
A NullReferenceException
is thrown when we are trying to access Properties of a null object or when a string value becomes empty and we are trying to access string methods.
当我们试图访问null对象的属性或字符串值变为空时,我们尝试访问字符串方法时抛出一个NullReferenceException。
For example:
例如:
-
When a string method of an empty string accessed:
当被访问的空字符串的字符串方法:
string str = string.Empty; str.ToLower(); // throw null reference exception
-
When a property of a null object accessed:
当一个空对象的属性被访问:
Public Class Person { public string Name { get; set; } } Person objPerson; objPerson.Name /// throw Null refernce Exception
#18
26
TL;DR: Try using Html.Partial
instead of Renderpage
TL;博士:尝试使用Html。部分代替Renderpage
I was getting Object reference not set to an instance of an object
when I tried to render a View within a View by sending it a Model, like this:
当我试图通过发送一个模型来呈现视图时,我得到的对象引用没有设置为对象的实例,就像这样:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Debugging showed the model was Null inside MyOtherView. Until I changed it to:
调试显示模型在MyOtherView中为Null。直到我把它改成:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
And it worked.
它工作。
Furthermore, the reason I didn't have Html.Partial
to begin with was because Visual Studio sometimes throws error-looking squiggly lines under Html.Partial
if it's inside a differently constructed foreach
loop, even though it's not really an error:
此外,我没有Html的原因。部分开始是因为Visual Studio有时会在Html下抛出错误的曲线。部分如果它在一个不同构造的foreach循环中,即使它不是一个真正的错误:
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
But I was able to run the application with no problems with this "error". I was able to get rid of the error by changing the structure of the foreach
loop to look like this:
但是我能够运行这个应用程序,并没有遇到这个“错误”。我可以通过改变foreach循环的结构来摆脱这个错误:
@foreach(var M in MyEntities){
...
}
Although I have a feeling it was because Visual Studio was misreading the ampersands and brackets.
虽然我感觉这是因为Visual Studio误读了ampersands和括号。
#19
17
What can you do about it?
你能做些什么呢?
There is a lot of good answers here explaining what a null reference is and how to debug it. But there is very little on how to prevent the issue or at least make it easier to catch.
这里有很多很好的答案来解释空引用是什么以及如何调试它。但是,关于如何防止这个问题,或者至少让它更容易被抓住,几乎没有。
Check arguments
检查参数
For example, methods can check the different arguments to see if they are null and throw an ArgumentNullException
, an exception obviously created for this exact purpose.
例如,方法可以检查不同的参数,看看它们是否为null,并抛出一个ArgumentNullException,这显然是为这个目的而创建的异常。
The constructor for the ArgumentNullException
even takes the name of the parameter and a message as arguments so you can tell the developer exactly what the problem is.
ArgumentNullException的构造函数甚至将参数的名称和一个消息作为参数,这样您就可以确切地告诉开发人员问题是什么。
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Use Tools
使用工具
There are also several libraries that can help. "Resharper" for example can provide you with warnings while you are writing code, especially if you use their attribute: NotNullAttribute
还有一些库可以提供帮助。例如,“Resharper”可以在你编写代码时向你提供警告,特别是如果你使用他们的属性:NotNullAttribute。
There's "Microsoft Code Contracts" where you use syntax like Contract.Requires(obj != null)
which gives you runtime and compile checking: Introducing Code Contracts.
这里有“微软代码契约”,你可以使用类似于契约的语法。需要(obj != null),它提供运行时和编译检查:引入代码契约。
There's also "PostSharp" which will allow you to just use attributes like this:
还有“PostSharp”,它允许你只使用这样的属性:
public void DoSometing([NotNull] obj)
By doing that and making PostSharp part of your build process obj
will be checked for null at runtime. See: PostSharp null check
通过这样做,将在运行时检查您的构建过程的后半部分。看:PostSharp null检查
Plain Code Solution
纯代码解决方案
Or you can always code your own approach using plain old code. For example here is a struct that you can use to catch null references. It's modeled after the same concept as Nullable<T>
:
或者您也可以使用简单的旧代码编写自己的方法。例如,这里有一个结构,您可以使用它来捕获空引用。它的模型与Nullable
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
You would use very similar to the same way you would use Nullable<T>
, except with the goal of accomplishing exactly the opposite - to not allow null
. Here are some examples:
您将使用非常类似于使用Nullable
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
is implicitly cast to and from T
so you can use it just about anywhere you need it. For example, you can pass a Person
object to a method that takes a NotNull<Person>
:
NotNull< t>被隐式地转换为T,因此您可以在任何需要的地方使用它。例如,您可以将Person对象传递给一个方法,该方法接受NotNull
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
As you can see above as with nullable you would access the underlying value through the Value
property. Alternatively, you can use an explicit or implicit cast, you can see an example with the return value below:
正如您可以在上面看到的那样,可以通过值属性访问潜在的值。或者,您可以使用显式或隐式转换,您可以看到一个带有返回值的示例:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Or you can even use it when the method just returns T
(in this case Person
) by doing a cast. For example, the following code would just like the code above:
或者您甚至可以在方法返回T(在本例中为Person)时使用它。例如,下面的代码就像上面的代码:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Combine with Extension
结合扩展
Combine NotNull<T>
with an extension method and you can cover even more situations. Here is an example of what the extension method can look like:
将NotNull< t>与扩展方法结合起来,您可以覆盖更多的情况。下面是一个扩展方法的示例:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
And here is an example of how it could be used:
这里有一个例子,说明如何使用它:
var person = GetPerson().NotNull();
GitHub
GitHub
For your reference I made the code above available on GitHub, you can find it at:
为了您的参考,我在GitHub上提供了以上代码,您可以在:
https://github.com/luisperezphd/NotNull
https://github.com/luisperezphd/NotNull
Related Language Feature
相关的语言功能
C# 6.0 introduced the "null-conditional operator" that helps with this a little. With this feature, you can reference nested objects and if any one of them is null
the whole expression returns null
.
c# 6.0引入了“空条件操作符”,它可以帮助解决这个问题。有了这个特性,就可以引用嵌套对象,如果其中任何一个都是null,那么整个表达式将返回null。
This reduces the number of null checks you have to do in some cases. The syntax is to put a question mark before each dot. Take the following code for example:
这减少了在某些情况下必须执行的空检查的数量。语法是在每个点之前加一个问号。以下列代码为例:
var address = country?.State?.County?.City;
Imagine that country
is an object of type Country
that has a property called State
and so on. If country
, State
, County
, or City
is null
then address will be
null. Therefore you only have to check whether
addressis
null`.
假设国家是一个国家的对象,它有一个属性叫State,等等。如果国家、州、县或城市是空的,那么地址将会是benull。因此,你只需要检查一下是否有问题。
It's a great feature, but it gives you less information. It doesn't make it obvious which of the 4 is null.
这是一个很棒的功能,但它给你的信息更少。这并不能说明4的哪个是空的。
Built-in like Nullable?
内置可空吗?
C# has a nice shorthand for Nullable<T>
, you can make something nullable by putting a question mark after the type like so int?
.
c#对于Nullable
It would be nice if C# had something like the NotNull<T>
struct above and had a similar shorthand, maybe the exclamation point (!) so that you could write something like: public void WriteName(Person! person)
.
如果c#有一些类似于NotNull< t>结构的东西,并且有类似的简写,也许是感叹号(!),这样你就可以写一些东西:public void WriteName(人!人)。
#20
6
You can fix NullReferenceException in a clean way using Null-conditional Operators in c#6 and write less code to handle null checks.
您可以使用c#6中的空条件操作符以一种干净的方式修复NullReferenceException,并编写更少的代码来处理null检查。
It's used to test for null before performing a member access (?.) or index (?[) operation.
在执行成员访问(?)或索引(?)操作之前,它用于测试null。
Example
例子
var name = p?.Spouse?.FirstName;
is equivalent to:
等价于:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
The result is that the name will be null when p is null or when p.Spouse is null.
结果是当p为null或p时,名称将为null。配偶是null。
Otherwise, the variable name will be assigned the value of the p.Spouse.FirstName.
否则,变量名将被赋值给p.Spouse.FirstName。
For More details : Null-conditional Operators
更多细节:空条件操作符。
#21
5
The error line "Object reference not set to an instance of an object. " states that you have not assigned instance object to a object reference and still you are accessing properies/methods of that object.
错误行“对象引用没有设置为对象的实例。“声明您没有将实例对象分配给对象引用的状态,并且您仍然在访问该对象的属性/方法。
for example: let say you have a class called myClass and it contains one property prop1.
例如:假设您有一个名为myClass的类,它包含一个属性prop1。
public Class myClass
{
public int prop1 {get;set;}
}
Now you are accessing this prop1 in some other class just like below:
现在你在其他类中访问这个prop1,就像下面这样:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
above line throws error because reference of class myClass is declared but not instantiated or an instance of object is not assigned to referecne of that class.
上面的行抛出错误,因为声明了类myClass的引用,但是没有实例化或对象的实例没有被分配给该类的引用。
To fix this you have to instantiate (assign object to reference of that class).
要修复这个问题,您必须实例化(分配对象以引用该类)。
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
#22
5
Interestingly, none of the answers on this page mention the two edge cases, hope no one minds if I add them:
有趣的是,在这个页面上没有一个答案提到这两个边缘案例,希望我添加它们时没有人会介意:
Edge case #1: concurrent access to a Dictionary
Generic dictionaries in .NET are not thread-safe and they sometimes might throw a NullReference
or even (more frequent) a KeyNotFoundException
when you try to access a key from two concurrent threads. The exception is quite misleading in this case.
. net中的通用字典不是线程安全的,有时候,当您试图从两个并发线程访问密钥时,它们可能会抛出一个NullReference甚至(更频繁地)一个KeyNotFoundException。在这种情况下,这个例外是很有误导性的。
Edge case #2: unsafe code
If a NullReferenceException
is thrown by unsafe
code, you might look at your pointer variables, and check them for IntPtr.Zero
or something. Which is the same thing ("null pointer exception"), but in unsafe code, variables are often cast to value-types/arrays, etc., and you bang your head against the wall, wondering how a value-type can throw this exception.
如果一个NullReferenceException被不安全的代码抛出,您可能会查看您的指针变量,并检查它们的IntPtr。零个或一些东西。也就是“空指针异常”,但是在不安全的代码中,变量通常被转换成值类型/数组等,然后你将头撞到墙上,想知道一个值类型如何抛出这个异常。
(Another reason for non-using unsafe code unless you need it, by the way)
(另一个不使用不安全代码的原因,除非你需要它)
#23
1
NullReferenceException or Object reference not set to an instance of an object occurs when an object of the class you are trying to use is not instantiated. For example:
当您试图使用的类的对象没有实例化时,不设置为对象实例的NullReferenceException或对象引用。例如:
Assume that you have a class named Student.
假设您有一个名为Student的类。
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Now, consider another class where you are trying to retrieve the student's full name.
现在,考虑另一个类,您正在尝试检索学生的全名。
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
As seen in the above code, the statement Student s - only declares the variable of type Student, note that the Student class is not instantiated at this point. Hence, when the statement s.GetFullName() gets executed, it will throw the NullReferenceException.
正如上面的代码中所看到的,语句学生只声明了类型Student的变量,注意到Student类在这一点上没有实例化。因此,当语句s.GetFullName()被执行时,它将抛出NullReferenceException。
#24
0
Well, in simple terms:
好吧,简单地说:
You are trying to access an object that isn't created or currently not in memory.
您正在尝试访问一个没有创建或当前没有内存的对象。
So how to tackle this:
如何解决这个问题:
-
Debug and let the debugger break... It will directly take you to the variable that is broken... Now your task is to simply fix this.. Using the new keyword in the appropriate place.
调试并让调试器中断…它会直接把你带到被破坏的变量…现在你的任务就是解决这个问题。在适当的位置使用新关键字。
-
If it is caused on some database commands because the object isn't present then all you need to do is do a null check and handle it:
如果它在某些数据库命令上引起,因为对象不存在,那么您所需要做的就是做一个空检查并处理它:
if (i == null) { // Handle this }
-
The hardest one .. if the GC collected the object already... This generally occurs if you are trying to find an object using strings... That is, finding it by name of the object then it may happen that the GC might already cleaned it up... This is hard to find and will become quite a problem... A better way to tackle this is do null checks wherever necessary during the development process. This will save you a lot of time.
最难的一个。如果GC已经收集了对象…如果您试图使用字符串查找对象,通常会出现这种情况。也就是说,根据对象的名称找到它,GC可能已经清理了它……这很难找到,而且将成为一个相当大的问题……解决这一问题的更好方法是在开发过程中任何必要的地方进行空检查。这会节省你很多时间。
By finding by name I mean some framework allow you to FIndObjects using strings and the code might look like this: FindObject("ObjectName");
通过查找名称,我的意思是一些框架允许您使用字符串进行FIndObjects,而代码可能是这样的:FindObject(“ObjectName”);
#25
0
If we consider common scenarios where this exception can be thrown, accessing properties withing object at the top.
如果我们考虑可以抛出这个异常的常见场景,那么访问位于顶部的属性withing对象。
Ex:
例:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
in here , if address is null , then you will get NullReferenceException.
在这里,如果地址为空,那么您将获得NullReferenceException。
So, as a practice we should always use null check, before accessing properties in such objects (specially in generic)
因此,作为一种实践,在访问这些对象的属性之前,我们应该始终使用空检查(特别是在通用对象中)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
#26
0
Reference types default to null to indicate that they are not referencing any object. Hence, if you try and access the object that is being referenced and there isn't one, you will get a NullReferenceException.
引用类型默认为null,表示它们没有引用任何对象。因此,如果您尝试访问被引用的对象,并且没有一个对象,那么您将获得一个NullReferenceException。
For Ex:
为例:
SqlConnection connection = null;
connection.Open();
When you run this code, you will get :
当您运行此代码时,您将得到:
System.NullReferenceException: Object reference not set to an instance of an object.
You can avoid this error by coding like this:
你可以这样编码来避免这个错误:
if (connection != null){
connection.Open();
}
Note: In order to avoid this error you should always initialize your objects before you try to do anything with them.
注意:为了避免这个错误,您应该在尝试使用对象之前初始化对象。
#27
-1
It means you are trying to manipulate something which has reference but not yet initialized
The first thing to do here is check every instance created.
Use breakpoints , watches , inspect your varibale values.
Follow stack trace and search for exact row and column which is creating problem
这意味着你在尝试操作一些有引用但尚未初始化的东西,首先要检查创建的每个实例。使用断点、手表、检查您的变量值。跟踪堆栈跟踪并查找正在创建问题的行和列。
#28
-1
If one is getting this message during saving or compiling the build, just close all the files and then open any file to compile and save.
如果在保存或编译构建过程中收到此消息,只需关闭所有文件,然后打开任何文件以编译和保存。
For me the reason was that I had rename the file and old file was still open.
对我来说,原因是我重命名了文件,旧文件仍然是打开的。
#29
-1
To use methods and member of an object you first have to create that object. If you didn't create it (variable that should hold the object is not initialized), but you try to use it's methods or variables you'll get that error.
要使用方法和对象的成员,首先必须创建该对象。如果您没有创建它(应该保存该对象的变量没有初始化),但是您尝试使用它的方法或变量,您将会得到这个错误。
Sometime you may just forgot to do initialization.
有时你可能忘记了初始化。
Edited: new can't return null, but fire's exception when failed. Long time ago it was the case in some languages, but not any more. Thanks @John Saunders for pointing that out.
编辑:new不能返回空值,但失败时触发异常。很久以前,在某些语言中是这样的,但现在不再是了。感谢@John Saunders指出这一点。
#30
-1
Literally the easiest way to fix a NullReferenceExeption has two ways. If you have a GameObject for example with a script attached and a variable named rb (rigidbody) this variable will start null when you start your game.
This is why you get a NullReferenceExeption because the computer does not have data stored in that variable.
从字面上看,解决nullreferenceex的最简单方法有两种方法。如果您有一个带有脚本的GameObject和一个名为rb(刚体)的变量,当您开始游戏时,这个变量将开始为空。这就是为什么您会得到一个nullreferenceex,因为计算机没有存储在该变量中的数据。
I'll be using a RigidBody variable as an example.
We can add data really easily actually in a few ways:
我将使用刚体变量作为例子。我们可以很容易地在几个方面添加数据:
- Add a RigidBody to your object with AddComponent > Physics > Rigidbody
Then go into your script and typerb = GetComponent<Rigidbody>();
This line of code works best under yourStart()
orAwake()
functions. - 在您的对象中添加一个刚体,AddComponent >物理>刚体然后进入您的脚本,并输入rb = GetComponent< RigidBody >();这一行代码在您的启动()或唤醒()函数下工作得最好。
- You can add a component programmatically and assign the variable at the same time with one line of code:
rb = AddComponent<RigidBody>();
-
您可以以编程方式添加组件,并在同一时间用一行代码来分配变量:rb = AddComponent
();
Further Notes: If you want unity to add a component to your object and you might have forgotten to add one, you can type [RequireComponent(typeof(RigidBody))]
above your class declaration (the space below all of your usings).
Enjoy and have fun making games!
进一步说明:如果您希望unity为您的对象添加一个组件,并且您可能忘记添加一个组件,那么您可以在您的类声明(您的所有usings下面的空间)上键入[RequireComponent(typeof(RigidBody))]。尽情享受制作游戏的乐趣吧!