【问题标题】:What is difference between initializing object with new and without new用 new 和不用 new 初始化对象有什么区别
【发布时间】:2017-05-13 20:49:34
【问题描述】:

这两个代码有什么区别:

MyClass a = new MyClass();
a = "something"

MyClass a = "something";

在第一个代码中,它创建了 MyClass 对象的新副本。 但是当不使用 new 关键字时会发生什么?会影响初始类(MyClass)吗?

【问题讨论】:

  • 第二个无效,不起作用。
  • @rory.ap - 没必要,可以在 MyClass 上定义隐式运算符。
  • @OndrejSvejdar -- 当然,你是对的。但我怀疑这就是他或她所拥有的。
  • 你确定你不是真的想知道MyClass a = { ... } 使用括号吗?
  • 假设stringMyClass 之间有一个未说明的隐式转换运算符,如果发现与这个问题相关,我会大吃一惊。

标签: c# .net


【解决方案1】:

嗯,第二种形式是非法的,除非定义了转换运算符。

要实现此转换运算符,您必须使用new MyClass 来构造一个新实例。

所以只要第二种形式完全合法,方法和最终结果都是一样的。

转换运算符示例:

public class MyClass
{
    public static implicit operator MyClass(string s)
    {
        return new MyClass();
    }
}

请注意,此转换运算符也处理此行:

a = "something";

这只是用转换运算符返回的新引用覆盖存储在a 中的原始引用。

转换运算符定义了一个名为 op_Implicit(在本例中)的静态方法,该方法将被调用,因此您的代码实际上看起来像这样:

MyClass a = new MyClass();
a = MyClass.op_Implicit("something");

或者这个:

MyClass a = MyClass.op_Implicit("something");

如果您可以阅读IL,您可以使用LINQPad 验证这一点。

这段代码:

void Main()
{
    MyClass a = "something";
    a = "xyz";
}

翻译成这个 IL:

IL_0000:  nop         
IL_0001:  ldstr       "something"
IL_0006:  call        UserQuery+MyClass.op_Implicit
IL_000B:  stloc.0     // a
IL_000C:  ldstr       "xyz"
IL_0011:  call        UserQuery+MyClass.op_Implicit
IL_0016:  stloc.0     // a
IL_0017:  ret  

注意对op_Implicit 的两次调用。

现在,如果您实现转换运算符,那么:

MyClass a = new MyClass();
a = "something"                      // error

MyClass a = "something";             // error

两种情况下的错误消息都是:

CS0029
无法将类型“字符串”隐式转换为“MyClass”

【讨论】:

    【解决方案2】:

    如果删除"something" 周围的双引号,并且something 是包含MyClass 实例的变量的名称,那么两者都可以工作。

    即,如果代码是: 案例一:

    MyClass something - new MyClass();
    MyClass a = new MyClass();
    a = something;   -- <--- This overwrites a with a different instance of 
                     --      MyClass, and leaves original instance in [a]
                     --      orphaned and subject to garbage collection.
    

    或者,案例 2:

    MyClass something - new MyClass();
    MyClass a = something;
    

    那么两者都很好。并且这两种形式之间没有区别,除了在您的源代码中,一种在一个语句中表示,另一种在两个语句中表示。在这两种形式中,底层代码都在执行两个单独的操作,在堆上为MyClass 的实例分配内存,以及创建和初始化一个指针变量(something),填充该变量的地址实例。如果发现两者在底层中间语言 (IL) 代码中完全相同,我不会感到惊讶。

    唯一的区别(在我上面的代码示例中)是操作完成后的状态。在上面的 case1 中,创建了两个 MyClass 实例,一个由变量 something 表示,一个由变量 a 表示。然后变量asomething 中的地址覆盖,使最初在something 中创建的变量成为孤儿并接受垃圾回收。

    在上面的案例 2 中,仅在第一行 (MyClass something - new MyClass(); MyClass a = something;) 中创建了一个 MyClass 实例。在同一行中,此实例的地址被放置在变量 'something. assigningsomethingtoain the second line does notcreate a new instance ofMyClass` 中,它只是创建了一个新的引用变量,该变量现在也指向同一个实例。

    所以这两种情况的区别在于,在第一种情况下,创建了两个实例,其中一个是孤立的(第二个),而在第二种情况下,只创建了一个实例。在这两种情况下,您最终都会得到两个变量(asomething)都指向同一个实例。

    【讨论】:

    • 我相信我错过了一些东西。让我仔细检查一下教程然后回来。
    猜你喜欢
    • 1970-01-01
    • 2018-08-02
    • 2011-11-22
    • 1970-01-01
    • 2011-04-10
    • 2018-06-04
    • 2012-12-29
    • 1970-01-01
    相关资源
    最近更新 更多