替换堆上的对象?

时间:2015-11-18 13:04:15

标签: c# object reference

也许这真的很简单或违反了所有规则,或者我只是不知道它叫什么,所以我找不到它。

无论如何,我希望能够替换堆上的整个对象。我添加了一个小代码示例,以显示我想要做的事情,以及一种方法,但我只是想知道是否有更优雅的方式?

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 个答案:

答案 0 :(得分:2)

  

必须有一种更优雅的方式吗?

你遗失了一件基本的东西。当您在列表中搜索对象时,如果找到一个对象,则会返回指向该对象的副本。这意味着当你改变它时,你只是在改变副本。列表中的原始引用仍然指向同一个旧对象实例。

  

但如果我没有列表怎么办?我只是在一个对象引用   变量?

然后您可以使用ref keyword通过引用传递引用类型

final String PRE_HTML = "<html><p style=\"text-align: left; width: 230px\">"; 
final String POST_HTML = "</p></html>"; 

tabbedpane.setTitleAt(0, PRE_HTML + "your title" + POST_HTML);
tabbedpane.setTitleAt(2, PRE_HTML + "your title 2" + POST_HTML);

答案 1 :(得分:0)

另一种解决方法是使用谚语&#34;额外的间接水平&#34;。

而不是将对象存储在列表中,而是存储包装器对象。包装器对象提供了一个&#34; Item&#34;指向实际对象的字段。然后你可以更新&#34;项目&#34;字段将其指向新对象。

一个简单的通用包装类可能如下所示:

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;
        }
    }
}