【问题标题】:C# inherited field value getting mixed up with base class' field valueC# 继承的字段值与基类的字段值混淆
【发布时间】:2012-01-31 01:06:40
【问题描述】:

我正在尝试将“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' 有趣的部分来了:'data' 的监视显示 ID 属性的值为 1。同时,'data.ID' 属性的值显示为 0。

我很确定这个错误与继承有关。我应该如何更改我的代码,以免出现此错误?

【问题讨论】:

  • 为什么要使用 new 运算符将 ID 隐藏在 MyClass 中的 MyBaseClass 中?该变量是公开的,并由您的MyClass 继承。

标签: c# generics inheritance properties hierarchy


【解决方案1】:

您需要删除此行:

public new int 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);            
        }
    }
}

【讨论】:

  • 谢谢,这解决了问题。当我尝试不同的方法时,隐藏是一个剩余的东西。在您建议的更改之后完美运行。
【解决方案2】:

问题是您指定了where T : MyBaseClass。这意味着data foreach 循环变量将是MyBaseClass 类型。所以data.ID 的唯一可访问值将是基类的版本。

See this write-up about it.

您必须将 data 类型转换为 MyClass 类型,或者始终使用基类 ID 字段(这是 zespri 所建议的)。

【讨论】:

  • 感谢您找到这篇文章 =)
  • 感谢您的链接,C# 很漂亮 :-)
猜你喜欢
  • 2021-06-08
  • 2019-05-14
  • 1970-01-01
  • 2012-09-20
  • 1970-01-01
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多