C#继承的字段值与基类的字段值混淆

时间:2012-01-31 01:06:41

标签: c# generics inheritance properties hierarchy

我正在尝试将“MyClass”的实例序列化为XML文件,一次一个。每个实例都有一个名为“ID”的int属性。目标文件已经有一些相同类型的项目,我将在这些项目之后附加新项目。我希望将要插入的实例的ID值比XML中最大的现有项高1。

我有以下通用类:

public class ContentDataManager<T> where T : MyBaseClass
{
    private static string _contentLocation = "Content/Data/";
    private const string DEFAULT_FILEPATH = "data.xml";

    public static int GetNextId(string filepath = DEFAULT_FILEPATH)
    {
        var allData = DeserializeAll(filepath);
        int largestId = 0;
        foreach (T data in allData)
        {
            if (data.ID > largestId)
            {
                largestId = data.ID;
            }
        }
        return largestId + 1;
    }
//...
}

我正在使用这个类:

public class MyClass : MyBaseClass
{
    public string Name;
    public float Size;
    public new int ID;

    public static MyClass CreateNew(string name, float size)
    {
        MyClass newClass = new MyClass();
        newClass.Name = name;
        newClass.Size = size;
        newClass.ID = ContentDataManager<MyClass>.GetNextId(DefaultFilepath);
        return newClass;
    }

MyBaseClass看起来像这样:

public abstract class MyBaseClass
{
    //...
    [ContentSerializerIgnore]
    public int ID = 0;
}

问题是,在ContentDataManager.GetNextId(...)方法的foreach循环中,有一个if语句实际上无法正常工作。当我调试时,我添加了两个手表:'data'和'data.ID' 以下是有趣的部分:“数据”监视显示ID属性的值为1.在sime时间,“data.ID”属性显示值为0.

我很确定这个错误与继承有关。我应该如何更改我的代码,以便我不会收到此错误?

2 个答案:

答案 0 :(得分:2)

您需要删除此行:

public new int ID;

根据您显示的内容,派生类中不需要单独的ID,基本的ID就可以了。当然,如果您希望序列化ID,则还需要删除ContentSerializerIgnore属性。

这是一个示例,用于演示当您使用'new'关键字声明成员时,您将为基类成员创建完全不相关的成员。

using System;

namespace Test
{
    abstract class  Base
    {
        public string Data;
    }

    class Derived : Base
    {
        // this is a separate field, has nothing in common with the base class field but name
        new public string Data;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Derived test = new Derived();

            //Let's set the Data field in the derived class
            test.Data = "Derived";

            //Now let's set this field in the base class
            Base cast = test;
            cast.Data = "Base";

            //We can see that the feild in the derived class has not changed
            //This will print 'Derived'
            Console.WriteLine(test.Data);

            // Just to make sure that a new object has not been constructed by a miracale
            // let's pass our object to a function that will display the Data field from
            // the base class
            Test(test);
        }

        static void Test(Derived test)
        {
            // When called from the Main above this will print 'Base'
            Console.WriteLine(((Base)test).Data);            
        }
    }
}

答案 1 :(得分:1)

问题在于您已指定where T : MyBaseClass。这意味着data foreach循环变量的类型为MyBaseClass。因此data.ID唯一可访问的值将是基类的版本。

See this write-up about it.

您必须输入强制转换data作为MyClass类型,或者始终使用基类ID字段(zespri建议的那样)。