【问题标题】:C# property value is by reference for some and by value for others [duplicate]C# 属性值对于某些是通过引用,对于其他是通过值[重复]
【发布时间】:2021-01-23 03:23:31
【问题描述】:

我不确定下面代码的问题在哪里,其中一个类实例的值会改变另一个类实例的值。似乎我有类型类的问题属性,其中一个类中设置的值会影响同一类型的另一个类的值。示例如下。我想要实现的是在从一个类(结果 2)分配值之后,对另一个类的后续操作不会影响前一个类。

public class Address {
    public string Street {
        get;
        set;
    }
}

public class Person {
    public string Name { 
        get; 
        set; 
    }

    public List<Address> Addresses { 
        get; 
        set; 
    } = new List<Address>();

    public int Age { 
        get; 
        set; 
    }
}

public class Employee {
    public string EmpID {
        get;
        set;
    }

    public Person EmployeePerson {
        get;
        set; 
    }
}

var emp = new Employee { 
    EmpID = "1", 
    EmployeePerson = new Person { 
        Name = "Alice", Addresses = 
        new List<Address> { 
            new Address { 
                Street = "123 Street" 
            }
        } 
    } 
};

var per = new Person { 
    Name = emp.EmployeePerson.Name, Addresses = emp.EmployeePerson.Addresses };

per.Addresses[0].Street = "New Street";
per.Name = "New Name";   

Console.WriteLine("Result 1: {0} , {1}", 
    emp.EmployeePerson.Name, per.Name);
    
Console.WriteLine("Result 2: {0} , {1}", 
    emp.EmployeePerson.Addresses[0].Street, per.Addresses[0].Street);

结果 1:爱丽丝,新名字

结果 2: 新街,新街

【问题讨论】:

  • Result 1: Alice , New Name Result 2: New Street , New Street 你期望的exact输出是什么?
  • 您提供的链接似乎是在不添加新自定义代码的情况下解决问题的最佳方法。

标签: c#


【解决方案1】:

List&lt;T&gt; 是一个引用类型。在您的示例中,emp.EmployeePersonper 都引用了同一个列表。如果您操作该列表,您将看到两个变量的变化。

您可以在通过复制旧列表初始化per 变量时创建一个新列表来避免这种情况。但是Address 也是一个引用类型,所以两个列表都包含对同一个实例的引用。您还必须复制地址变量。我在你的 Address 类中添加了一个 Copy() 方法:

var per = new Person { Name = emp.EmployeePerson.Name, Addresses = emp.EmployeePerson.Addresses.Select<Address,Address>(x => x.Copy()).ToList() };

public class Address
{
    public string Street {get;set;}
        
    public Address Copy()
    {
        return new Address { Street = this.Street };
    }
}

引用类型和值类型之间的区别在 C# 中非常重要。以下是官方文档中的一些信息:

https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/reference-types https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/value-types

【讨论】:

  • 如何分配地址而不将其转换为列表
  • 对不起,我以为 Address 是一个字符串列表。因为它是您的Address 类的列表,所以它有点复杂。您必须复制列表和 Address 类的实例
  • 将地址设为只读,如下所示:public List&lt;Address&gt; Addresses { get; } = new List&lt;Address&gt;();(即删除设置器)。然后不要分配地址,而是添加新地址:Addresses.Add(new Address {...})
  • 有没有更好的解决方法?我的意思是将引用类型转换为值类型。
  • List&lt;T&gt; 始终是引用类型。如果您希望 Address 也成为值类型,请将其从 class 更改为 struct。但在继续之前,我建议您多阅读,因为如果您不了解如何处理引用和值类型,您很快就会迷失方向。
猜你喜欢
  • 2021-11-23
  • 2021-12-31
  • 2021-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多