2015-11-18 52 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; 
     } 
    } 
}