0

如果您在 .NET 中创建一个类,它将是一个引用类型。在本例中,我在 SomeMethod 中设置 MyClass 的名称。现在在 Main 方法中,我真的不需要从 SomeMethod 分配返回值,因为传入的参数是引用类型。我希望 main 方法中的实例具有新的更新名称“John”,并且确实如此。

为了便于阅读,我经常将返回值分配回,即使在 main 中不需要将更新的属性重新分配给我的原始实例。我的假设是编译器足够聪明,不会在 Main 方法中重新创建 MyClass 的新引用。真的吗?或者编译器在为自己分配返回值时是否真的创建了一个新的引用并指向更新的值?

//My class will be a reference type
public class MyClass 
{
    public int ID { get; set; }
    public string name { get; set; }
}

public class Main
{
    //Main method of application
    public void Main()
    {
        MyClass myClass = new MyClass();
        //return value back to itself
        myClass = SomeMethod(myClass);
    }

    public MyClass SomeMethod(MyClass myClass)
    {
        myClass.name = "John";
        return myClass;
    }
}

这是IL

    instance void Main1 () cil managed 
{
    // Method begins at RVA 0x207c
    // Code size 15 (0xf)
    .maxstack 2
    .locals init (
        [0] class Test.MyClass myClass
    )

    IL_0000: newobj instance void Test.MyClass::.ctor()
    IL_0005: stloc.0
    IL_0006: ldarg.0
    IL_0007: ldloc.0
    IL_0008: call instance class Test.MyClass Test.Main::SomeMethod(class Test.MyClass)
    IL_000d: stloc.0
    IL_000e: ret
} // end of method Main::Main1
4

4 回答 4

2

It doesn't create a new reference.

But there isn't any point in returning it either. This should suffice:

 public void SomeMethod(MyClass myClass)
 {
    myClass.name = "John";

 }

The above is natural and actually less convoluted than the way you propose.

于 2012-10-12T19:49:33.337 回答
1

Classes are passed as reference to methods, so your are modifying the same thing as you are returning.

When an object based on a reference type is passed to a method, no copy of the object is made. Instead, a reference to the object being used as a method argument is made and passed. Changes made through this reference will therefore be reflected in the calling method.

Source: http://msdn.microsoft.com/en-us/library/ms173114(v=vs.80).aspx

Regarding the readability: your method should always be self-explanatory. The name of the method should in my opinion say something about what it does.

void AddClientContextToContainer(Container destination)
于 2012-10-12T19:49:23.650 回答
1

在您的情况下,您正在创建对象的一个​​实例。实际实例是通过new. 引用本质上只是一个整数(32 位系统上的 32 位,64 位系统上的 64 位)。该整数是指对象实例在内存中的位置。“创建一个新的引用”本质上与创建一个新整数的工作量相同(意思是非常非常少;它是计算机可以做的最小可能的工作单元)。

与替代方案相反,您的代码void将执行两个(冗余)引用副本。(一次将方法参数复制到堆栈上的返回值,然后再次从该返回值返回到原始变量。)

实际的额外工作量是微不足道的。它存在,但它真的很小。这里的关注点应该只是可读性之一。如果您发现该代码更易于阅读和理解,那很好。请注意,这是一种通常仅在MyClass不可变时使用的模式,其中返回值是对新实例的引用,而不是传入的实例。这可能会导致其他人阅读您的代码时感到困惑。如果他们错误地假设对象是不可变的,它可能会导致……坏事。

其他人建议让方法返回 void,但我想说让类变得不可变可能才有意义。您已经在遵循更不可变的模式。

于 2012-10-12T20:03:35.317 回答
1

要回答您的问题,是的,编译器足够聪明,不会将返回值重新分配给同一个对象。如果我们使用 Reflector 或 dotPeek 打开您的代码,您的代码:

public void Main()
{
    MyClass myClass = new MyClass();
    //return value back to itself
    myClass = SomeMethod(myClass);
}

只是转换为:

public void Main()
{
    this.SomeMethod(new MyClass());
}

即使我们对 reassign 变量做一些事情,它仍然会被编译器删除。例如,编译器将其转换为:

public void Main()
{
    MyClass myClass = new MyClass();
    //return value back to itself
    myClass = SomeMethod(myClass);

    Console.WriteLine(myClass.name);
}

对此:

public void Main()
{
    Console.WriteLine(this.SomeMethod(new MyClass()).name);
}

但就像 Lews Therin 和 Robert Jeppesen 所说,你不应该这样做,因为这是不好的做法,可能会导致误解

于 2012-10-12T20:16:17.237 回答