1

我有以下代码:

public void Start()
    {
        List<StructCustomer> listCustomer = new List<StructCustomer>();

        listCustomer.Add(
            new StructCustomer { ID = 0, name = "Any Default Name", birthday = DateTime.Now });


        DoSomethingWithStructList(listCustomer);
        StructCustomer customer = listCustomer.First();
        Console.WriteLine("ID = {0}, Name = {1}", customer.ID, customer.name); // Writes ID = 0, Name = "Any Default Name"

    }

public void DoSomethingWithStructList(List<StructCustomer> listStructs)
        {
            StructCustomer test = listStructs.First();
            test.ID = 2;
            test.name = "Edited by method";
            Console.WriteLine("ID = {0}, Name = {1}", test.ID, test.name); // Writes "ID = 2, Name = Edited by method"
        }

 public struct StructCustomer
        {
            public int ID { get; set; }
            public string name { get; set; }
            public DateTime birthday { get; set; }
        }

如您所见,变量 List 是对客户列表的引用。不应该在列表的 StructCustomer 变量中编辑值吗?

我知道结构是价值而不是引用类型,但我将它装箱在一个列表中!

4

4 回答 4

1

Creating a list of a structure type will cause each item of the list to encapsulate all of the fields within the structure. The list's indexed 'get' method will copy all of the fields associated with a list item to the corresponding fields of the return value; the indexed 'put' will copy all of the fields from the passed-in item to the corresponding fields associated with the appropriate list item. Note that neither the 'get' nor the 'put' creates any attachment between the item in the list and the item which is read or written; future changes to one will not affect the other.

For many kinds of programs, this kind of detachment will sometimes be desirable and sometimes not. To help facilitate such cases, I would suggest creating a type like:

class SimpleHolder<T> { public T Value; /* A field, not a property! */ }

and then using a List<SimpleHolder<StructCustomer>>.

Your class should create every SimpleHolder<StructCustomer> instance itself, and never expose references to any of those instances to outside code. If you want to have a method, e.g. return item 0, use:

StructCustomer FirstCustomer()
{ 
  return listStructHolders[0].Value;
}

To store a passed-in value:

void AddCustomer(StructCustomer newCustomer)
{
  var temp = new SimpleHolder<StructCustomer>();
  temp.Value = newCustomer;
  listStructHolders.Add(temp);
}

To modify the name of customer 3:

listStructHolder[3].Value.name = "Fred";

Using a simple "exposed-field holder" class will make it easy to combine the advantages of structure types and mutable classes.

于 2013-09-04T21:18:39.210 回答
1

结构是值类型,因此,当您从列表中检索它们时,如在您的示例中,您检索的是其值的副本。然后你修改它。这不会更改列表中包含的原始内容中的任何内容。

如果要更改列表中的元素,请执行以下操作:

listStructs[0].ID = 2;
listStrings[0].name = "Edited by method";
于 2013-09-02T01:20:50.943 回答
1

好吧,当你这样做时:

StructCustomer test = listStructs.First();
test.ID = 2;
test.name = "Edited by method";
Console.WriteLine("ID = {0}, Name = {1}", test.ID, test.name);

您实际上是在创建 listStructs 中第一个结构的副本,因此,您将更改副本的值,而不是真实的值。尝试这样做 - 它应该有效:

listStructs.First().ID = 2;
listStructs.First().name = "Edited by method";

所以,就是这样;) OBS:这种方法不是由 CPU 使用率推荐的,但是,它是一种出路=)

于 2013-09-02T01:30:27.607 回答
0

List 包含值类型,因此当您向它询问项目时它会返回一个值。尝试制作一个列表,您会看到相同的行为。

因此,您需要直接对列表中的列表项进行分配。通过在 foreach 循环中迭代列表,您可以使行为在语义上更接近您尝试执行的操作。

于 2013-09-02T01:32:19.673 回答