Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# A=new A()和A=null之间的差异_C#_Heap Memory - Fatal编程技术网

C# A=new A()和A=null之间的差异

C# A=new A()和A=null之间的差异,c#,heap-memory,C#,Heap Memory,在C#中 这三条线是如何与记忆相关的 我知道第一行将在堆中创建内存,但剩下的两行呢 如果, A A; 是一个字段和局部变量 第二条和第三条语句相同,即分配一个空引用,指向“null”; 第一个将在托管堆中分配一个类的新实例,并将其地址分配给一个引用变量 创建a的新实例,并将其分配给变量a 什么也不做。它只是将null分配给引用a。如果未使用a,编译器可能会对其进行优化 什么也不做。它将恢复为A=默认值(A)与2相同,因为默认值(A)为null。对于方法变量,如果您不分配它,它将向您显示警告或错误

在C#中

这三条线是如何与记忆相关的

我知道第一行将在堆中创建内存,但剩下的两行呢

如果, A A;
是一个字段和局部变量

第二条和第三条语句相同,即分配一个空引用,指向“null”; 第一个将在托管堆中分配一个类的新实例,并将其地址分配给一个引用变量

  • 创建
    a
    的新实例,并将其分配给变量
    a
  • 什么也不做。它只是将
    null
    分配给引用
    a
    。如果未使用
    a
    ,编译器可能会对其进行优化
  • 什么也不做。它将恢复为
    A=默认值(A)
    与2相同,因为
    默认值(A)
    null
    。对于方法变量,如果您不分配它,它将向您显示警告或错误。如果不使用,这个也可以优化掉
  • A A=新A()
    这实际上实例化了一个a类型的新对象。a是对对象的引用。a存储在堆栈上,而实际对象存储在堆上

    A=null只在堆栈上创建引用-堆上没有数据

    A我认为这与
    A=null相同-编辑根据问题的上下文要求OP进行澄清。

    如果
    A
    是一个字段,例如

    所以

    是一个
    a
    类型的字段
    a
    ,其初始值为
    a
    的新实例;这两行相等(类型为
    a
    的字段
    a
    ,初始值为
    null
    值):

    字段的初始值,无论是静态字段还是静态字段 实例字段,是默认值“

    如果是局部变量,例如

    编译器不初始化局部变量

    所以


    假设
    A
    是引用类型,并且此代码位于方法中:

    A A=新A()
    将始终在堆上创建一个新对象,并为
    a
    分配对该新对象的引用

    A=null
    A
    会将
    null
    分配给
    a

    但是,为
    a a=null生成的IL可能存在差异
    A比较

    考虑以下简单程序:

      A a = new A(); // "a" of type "A" declaration with new instance of A as an initial value
      A a = null;    // "a" of type "A" declaration with null initial value
      A a;           // just "a" declaration, "a" contains trash and should be initialized before using
    
    为发布版本生成的IL如下所示:

    static void Main()
    {
        string s;
    
        if (Environment.TickCount > 0)
            s = "A";
        else
            s = "B";
    
        Console.WriteLine(s);
    }
    
    现在修改代码以将引用初始化为null:

    .method private hidebysig static void Main() cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] string s)
        L_0000: call int32 [mscorlib]System.Environment::get_TickCount()
        L_0005: ldc.i4.0 
        L_0006: ble.s L_0010
        L_0008: ldstr "A"
        L_000d: stloc.0 
        L_000e: br.s L_0016
        L_0010: ldstr "B"
        L_0015: stloc.0 
        L_0016: ldloc.0 
        L_0017: call void [mscorlib]System.Console::WriteLine(string)
        L_001c: ret 
    }
    
    IL对此进行了更改:

    static void Main()
    {
        string s = null;
    
        if (Environment.TickCount > 0)
            s = "A";
        else
            s = "B";
    
        Console.WriteLine(s);
    }
    
    .method private hidebysing static void Main()cil managed
    {
    .入口点
    .maxstack 2
    .init(
    [0]字符串(s)
    
    L_0000:ldnull所有三个构造都在堆栈上为局部作用域变量a分配一个引用

  • A=newa();
    在堆上构造一个对象(假设A是一个类,因为它的引用可以赋值为null)
  • 如果您的团队指南支持显式类型声明而不是
    var
    ,则此构造非常有用。在这种情况下,您可以使用
    var
    ,否则,编译器将推断类型:

    .method private hidebysig static void Main() cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] string s)
        L_0000: ldnull         <====== Lookie here
        L_0001: stloc.0        <====== and here
        L_0002: call int32 [mscorlib]System.Environment::get_TickCount()
        L_0007: ldc.i4.0 
        L_0008: ble.s L_0012
        L_000a: ldstr "A"
        L_000f: stloc.0 
        L_0010: br.s L_0018
        L_0012: ldstr "B"
        L_0017: stloc.0 
        L_0018: ldloc.0 
        L_0019: call void [mscorlib]System.Console::WriteLine(string)
        L_001e: ret 
    
  • A A=null;
    将null引用分配给A,如果要引入对引用的读取访问,这非常有用
  • 例如:

    var a = new A();
    
    您可以只使用以下键序列: var a=x;(左)(左)(左)(Alt-Enter)…拆分声明和赋值…(Enter),然后在编辑器中获得显式声明:

    var x = container.GetFirst(); // some imaginary GetFirst method which returns an instance of non-keyboard friendly type.
    
    SomeVerylongTypeName a;
    a=x;
    
    什么是空引用,它将如何映射??它们不一样,因为
    A A=null;A b=A;
    不会导致编译错误,但
    A A;A b=A;
    会导致编译错误。从内存分配的角度来看,它们是相同的。编译器会在为引用赋值之前阻止您使用它,但是内存分配没有任何变化P问“这三行是如何与内存相关的?”请解释为什么在代码中,您可以轻松返回第2行而无需编辑它,但是第3行它会抱怨未初始化的变量。我建议您也可以查看此处的信息以了解有关null的更多信息:因为它未初始化,所以它会向您显示警告或错误(它不知道它是什么)。因为使用2时,您确实分配了一个值:
    null
    (它知道它是什么:它没有值)。当我说“抱怨”时,我的意思是它不允许您编译。所以(至少编译时间),第2行和第3行不是同一件事。@BjarkeSøgaard第2行和第3行是相同的,如果A是类,并且声明是类中的字段,因为字段(与局部变量相反)是否默认初始化,这相当于将其置零。cf.您是否声明了字段或局部变量?最后一行在这两种情况下的行为会有所不同。
    a
    a是类还是结构?请注意,您正在变得糟糕(IMO)因为你的问题不够清楚,所以答案是假设性的。上下文在这里有很大的不同。@Jon你能澄清一下吗?希望能从你这里学到一些东西:)@JonSkeet我的意思是将类a声明为字段和本地两种情况。然后你应该编辑你的问题来显示这一点,包括字段是否是字段结构或类的引用。回答您问题的人不必阅读注释来理解您的问题。引用仅当是局部变量或结构中的字段(也在堆栈上)时才会存储在堆栈上-在这种情况下,您的最终语句是不正确的。您是对的,但在第三行中,您说
    a
    A=null
    相同。块中的某些部分不能使用
    A.Anything
    ,因为它会在编译时表示未实例化变量,但如果将其赋值为null和
    .method private hidebysig static void Main() cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] string s)
        L_0000: call int32 [mscorlib]System.Environment::get_TickCount()
        L_0005: ldc.i4.0 
        L_0006: ble.s L_0010
        L_0008: ldstr "A"
        L_000d: stloc.0 
        L_000e: br.s L_0016
        L_0010: ldstr "B"
        L_0015: stloc.0 
        L_0016: ldloc.0 
        L_0017: call void [mscorlib]System.Console::WriteLine(string)
        L_001c: ret 
    }
    
    static void Main()
    {
        string s = null;
    
        if (Environment.TickCount > 0)
            s = "A";
        else
            s = "B";
    
        Console.WriteLine(s);
    }
    
    .method private hidebysig static void Main() cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] string s)
        L_0000: ldnull         <====== Lookie here
        L_0001: stloc.0        <====== and here
        L_0002: call int32 [mscorlib]System.Environment::get_TickCount()
        L_0007: ldc.i4.0 
        L_0008: ble.s L_0012
        L_000a: ldstr "A"
        L_000f: stloc.0 
        L_0010: br.s L_0018
        L_0012: ldstr "B"
        L_0017: stloc.0 
        L_0018: ldloc.0 
        L_0019: call void [mscorlib]System.Console::WriteLine(string)
        L_001e: ret 
    
    var a = new A();
    
    Func<int, int> factorial = null;
    factorial = n => n < 3 ? n : n * factorial(n-1);
    
    var x = container.GetFirst(); // some imaginary GetFirst method which returns an instance of non-keyboard friendly type.
    
    SomeVerylongTypeName<EvenMoreLongTypeName> a;
    a = x;