2015-11-18 51 views
1

也許這是真正簡單的或違反所有的規則,或者我只是不知道它叫什麼,所以我不能找到它。替換堆上的對象?

無論如何,我希望能夠替換堆上的整個對象。我已經添加了一個小代碼示例來展示我想要做什麼以及如何做,但我只想知道是否有更優雅的方式?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace BasicObjectTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Test> testList = new List<Test> 
      { 
       new Test {Value=1,NiceString="First" }, 
       new Test {Value=2,NiceString="Second" }, 
       new Test {Value=3,NiceString="Third" } 

      }; 

      var replacementTestClass = new Test { Value = 2, NiceString = "NEW" }; 
      EasyWay(testList, replacementTestClass); 

      var correctTestClass = testList.FirstOrDefault(x => x.Value == 2); 
      Console.WriteLine(correctTestClass.NiceString); //Expecting "Forth" 
      Console.ReadLine(); 

      HardWay(testList, replacementTestClass); 

      correctTestClass = testList.FirstOrDefault(x => x.Value == 2); 
      Console.WriteLine(correctTestClass.NiceString); 
      Console.ReadLine(); 
     } 

     private static void HardWay(List<Test> testList, Test replacementTestClass) 
     { 
      //This will work! 
      var secondTestClass = testList.FirstOrDefault(x => x.Value == 2); 

      CopyPropertiesUsingPropertyInfo(secondTestClass, replacementTestClass); 



     } 

     private static void CopyPropertiesUsingPropertyInfo(Test secondTestClass, Test replacementTestClass) 
     { 
      foreach(var pi in secondTestClass.GetType().GetProperties()) 
      { 
       pi.SetValue(secondTestClass, pi.GetValue(replacementTestClass, null)); 
      } 



     } 

     private static void EasyWay(List<Test> testList, Test replacementTestClass) 
     { 
      //This wont work, but I want it to! 

      var secondTestClass = testList.FirstOrDefault(x => x.Value == 2); 

      secondTestClass = replacementTestClass; 


     } 
    } 
} 

和我的測試對象

class Test 
{ 
    public int Value { get; set; } 
    public string NiceString { get; set; } 

} 

必須有這樣做的更優雅的方式? 我知道爲什麼第一個替代方法不起作用:我只是更改該變量的對象引用。

更新: 使用這種思想,我很長一段時間瞭解它,我現在認爲它會工作,但測試失敗。爲什麼?我沒有替換該對象,以便每個使用它的對象都應該使用新對象?見下面

[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void TestMethod1() 
    { 
     var main = new Main { Property = 1 }; 

     var dependent = new Dependent(main); 

     void ChangeRef(ref Main Oldmain, Main newMain) 
     { 
      Oldmain = newMain; 

     } 

     ChangeRef(ref main, new Main { Property = 5 }); 

     Assert.AreEqual(5,dependent.Main.Property); 
    } 
} 

public class Main 
{ 
    public int Property { get; set; } 


} 

public class Dependent 
{ 
    public Dependent(Main main) 
    { 
     Main = main; 
    } 

    public Main Main { get; set; } 

} 

回答

2

完整的代碼必須有這樣做的更優雅的方式?

有一個基本的東西你失蹤。當您搜索列表中的對象,並找到一個對象時,您將獲得指向該對象的引用副本。這意味着當你改變它時,你只會改變副本。列表中的原始引用仍然指向同一個舊對象實例。

但是如果我沒有列表。我只是在 變量中有對象引用?

然後你可以使用ref keyword參照傳遞引用類型

public static void Main(string[] args) 
{ 
    var test = new Test { Value = 1, NiceString = "First" }; 
    var newTest = new Test { Value = 2, NiceString = "AlteredTest!" }; 

    UpdateTest(ref test, newTest); 
    Console.WriteLine(test.NiceString); // "AlteredTest!" 
} 

public static void UpdateTest(ref Test originalTest, Test other) 
{ 
    originalTest = other; 
} 
+0

我不知道關於傳遞對象作爲參考。我已經將它用於值類型。 – Erik83

+0

@ Erik83引用類型也通過值***通過***。不同之處在於,該值實際上是指向虛擬內存中地址的引用,而不是像值類型那樣的實際字節。 –

0

另一種方式來處理,這是與衆所周知的「間接的額外水平」。

不是將對象存儲在列表中,而是存儲包裝器對象。包裝對象提供了一個指向實際對象的「Item」字段。然後,您可以更新「項目」字段以將其指向新對象。

一個簡單通用的包裝類可能是這樣的:

class Wrapper<T> 
{ 
    public T Item; 

    public Wrapper(T item) 
    { 
     Item = item; 
    } 

    public static implicit operator Wrapper<T>(T item) 
    { 
     return new Wrapper<T>(item);  
    } 
} 

那麼你可以使用它像這樣:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication2 
{ 
    class Test 
    { 
     public int Value { get; set; } 
     public string NiceString { get; set; } 
    } 

    class Wrapper<T> 
    { 
     public T Item; 

     public Wrapper(T item) 
     { 
      Item = item; 
     } 

     public static implicit operator Wrapper<T>(T item) 
     { 
      return new Wrapper<T>(item);  
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var testList = new List<Wrapper<Test>> 
      { 
       new Test {Value = 1, NiceString = "First"}, 
       new Test {Value = 2, NiceString = "Second"}, 
       new Test {Value = 3, NiceString = "Third"} 
      }; 

      var replacementTestClass = new Test { Value = 2, NiceString = "NEW" }; 
      EasyWay(testList, replacementTestClass); 

      var correctTestClass = testList.FirstOrDefault(x => x.Item.Value == 2); 
      Console.WriteLine(correctTestClass.Item.NiceString); //Expecting "New" 
      Console.ReadLine(); 
     } 

     private static void EasyWay(List<Wrapper<Test>> testList, Test replacementTestClass) 
     { 
      var secondTestClass = testList.FirstOrDefault(x => x.Item.Value == 2); 
      secondTestClass.Item = replacementTestClass; 
     } 
    } 
}