2012-03-04 116 views
0

这应该是一个基本的C#问题。假设我有一个Person类,其中包含一个名为Pets属性,它是一个List<Pet>通过将新对象分配给子实例来更新子对象

如果我想更新宠物,我可以将宠物作为变量并操作属性,但似乎无法创建新的宠物对象并将其分配给现有宠物对象。我得到了“分配的值不用于任何执行路径”警告。我创建了一些非常简单的代码来概述这个问题。

在我真正的代码中,我希望能够使用新的子对象并替换现有的对象。如果你能告诉我如何用下面的样本updatedCat做到这一点,我将不胜感激!

class Program 
{ 
    static void Main(string[] args) 
    { 
    var program = new Program(); 
    program.RunMe(); 
    } 

    public void RunMe() 
    { 
    var myPerson = new Person() { Name = "John Doe" }; 
    var dog = new Pet() { Type = "Dog", Name = "Woofie" }; 
    var cat = new Pet() { Type = "Cat", Name = "Chester" }; 
    myPerson.Pets.Add(dog); 
    myPerson.Pets.Add(cat); 
    Console.WriteLine("Initial Pet Status:"); 
    ListPets(myPerson); 

    var currentDog = myPerson.Pets.SingleOrDefault(p => p.Type == "Dog"); 
    currentDog.Name = "Snoopie"; 
    Console.WriteLine("\r\nPet Status After Updating Dog Directly (name should be 'Snoopie'):"); 
    ListPets(myPerson); 

    var updatedCat = new Pet() { Type = "Cat", Name = "Felix" }; 
    var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat"); 
    currentCat = updatedCat; 
    //Resharper shows "Value assigned is not used in any execution path" for the currentCat 
    //and the current cat is never updated 
    Console.WriteLine("\r\nPet Status After Trying to Update Cat by Assigning a New Cat to existing Cat (name should be 'Felix' but it's not):"); 
    ListPets(myPerson); 

    Console.ReadLine(); 
    } 

    public void ListPets(Person person) 
    { 
    foreach (var pet in person.Pets) 
    { 
     Console.WriteLine(string.Format(" {0} has a {1} named {2}", person.Name, pet.Type, pet.Name)); 
    } 
    } 
} 

public class Person 
{ 
    public string Name { get; set; } 
    public List<Pet> Pets { get; set; } 

    public Person() 
    { 
    Pets = new List<Pet>(); 
    } 
} 

public class Pet 
{ 
    public string Type { get; set; } 
    public string Name { get; set; } 
} 

编辑ID添加到宠物和创建InsertOrUpdatePet方法 (注:我除去简洁Console.WriteLine命令命令)

class Program 
{ 
    static void Main(string[] args) 
    { 
    var program = new Program(); 
    program.RunMe(); 
    } 

    public void RunMe() 
    { 
    var myPerson = new Person() { Name = "John Doe" }; 
    var dog = new Pet() { Id = 1, Type = "Dog", Name = "Woofie" }; 
    var cat = new Pet() { Id = 2, Type = "Cat", Name = "Chester" }; 
    myPerson.Pets.Add(dog); 
    myPerson.Pets.Add(cat); 

    var updatedCat = new Pet() { Id = 2, Type = "Cat", Name = "Felix" }; 
    InsertOrUpdatePet(myPerson, updatedCat); 

    var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat"); 
    } 


    public void InsertOrUpdatePet(Person person, Pet pet) 
    { 
    var currentPet = person.Pets.SingleOrDefault(p => p.Id == pet.Id); 
    if(currentPet == null) 
    { 
     person.Pets.Add(pet); 
    } 
    else 
    { 
     currentPet = pet; // This doesn't work 
     person.Pets.SingleOrDefault(p => p.Id == pet.Id) = pet; //This throws an error 
    } 
    } 

} 

public class Person 
{ 
    public string Name { get; set; } 
    public List<Pet> Pets { get; set; } 

    public Person() 
    { 
    Pets = new List<Pet>(); 
    } 
} 

public class Pet 
{ 
    public int Id { get; set; } 
    public string Type { get; set; } 
    public string Name { get; set; } 
} 
+1

后者不起作用。 – jason 2012-03-04 18:56:32

+0

看起来你还不了解对象和对象引用之间的区别。你可能想对此做一些研究。 – usr 2012-03-04 19:00:15

回答

1

这取决于你想在概念上做什么。如果你想说的是,人摆脱了旧猫和现在有一个新的猫,你应该做的是:删除旧的猫,然后将新的猫:

var updatedCat = new Pet() { Type = "Cat", Name = "Felix" }; 
var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat"); 
myPerson.Remove(currentCat); 
myPerson.Add(updatedCat); 

如果,另一方面,人仍然具有相同的猫,但猫改名,您应该重命名旧的猫,你与狗做同样的方式:

var currentCat = myPerson.Pets.SingleOrDefault(p => p.Type == "Cat"); 
currentCat.Name = "Felix"; 

您的代码不起作用,因为currentCat的东西,引用猫,而不是列表中的位置。正如Jason所建议的,如果你想用某种方式来表示列表中的位置,那么你可以使用索引到列表中。

+0

谢谢Svick。正如我在下面向杰森陈述的那样,并在我的编辑中显示的,如果我创建UpdateOrInsert方法并将更新后的宠物参数作为变量进入该方法,那么如何更新Person.Pets集合?由于我正在使用实体框架并且正在跟踪上下文,因此我希望保持该对象与刚刚更新的属性相同(因为它由EF跟踪)。 – bigmac 2012-03-04 19:22:08

1

你需要删除的宠物你想替换并添加一个新的宠物。

Alteratively,你可以说

person.Pets[index] = new Pet() { Type = "Cat", Name = "Felix" }; 

其中index是要更换宠物的索引。

你不明白的是,宠物列表仅仅是一个对宠物实例的引用列表。

获取对这些Pet实例之一的引用并将其存储在一个变量中,并为Pet的新实例分配一个引用不会改变List中引用的任何引用。当然不是,你还没有修改列表。这就是为什么您必须移除要替换的元素,并添加新元素,或直接将新实例的引用分配给要替换的元素。

+0

谢谢贾森......这开始有道理,但我编辑了我的原始问题,以更密切地显示我在我的真实代码中所做的事情。我想在我的业务层中有一个可以更新“宠物”的InsertOrUpdate方法(或者如果基于唯一的Id值不存在,则添加一个新的方法)。我在更新中遇到困惑。如果更新的宠物参数作为变量进入方法,我如何更新Person.Pets集合?那有意义吗? – bigmac 2012-03-04 19:20:14