【问题标题】:C# override base class property in generic classC# 覆盖泛型类中的基类属性
【发布时间】:2021-01-13 11:20:37
【问题描述】:

我对 C# 中的泛型类和继承有疑问。也许我在某个地方错了,这样的代码设计没有遵循最佳实践,但我真的希望让它发挥作用。我有以下类结构:

public class BaseInfo
{
    public int Id { get; set; }
}

public class BaseData
{
}

public class SomeClass
{
    public BaseData Data { get; protected set; }
    public BaseInfo Info { get; protected set; }
}

public class SomeClass<TData, TInfo> : SomeClass
    where TData : BaseData, new()
    where TInfo : BaseInfo, new()
{
    public new TData Data { get; protected set; }
    public new TInfo Info { get; protected set; }

    public SomeClass()
    {
        Data = new TData();
        Info = new TInfo();
    }
}

然后我指定了一个特定的类:

public class SpecificInfo : BaseInfo
{
    public int MaxNumber { get; set; }
}

public class SpecificData : BaseData
{
    public int StartFrom { get; set; }
}

public class SpecificClass : SomeClass<SpecificData, SpecificInfo>
{
    public SpecificClass(int startFrom, int maxNumber)
    {
        Data = new SpecificData
        {
            StartFrom = startFrom
        };

        Info = new SpecificInfo
        {
            Id = 1,
            MaxNumber = maxNumber
        };
    }
}

那我想在我的程序中使用它:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        var specific = new SpecificClass(100, 1000);

        Process(specific);
    }

    static void Process(SomeClass someClass)
    {
        var data = someClass.Data;

        if (data is SpecificData specificData)
        {
            Console.WriteLine($"This is specific data {specificData.StartFrom}");
        }
        else
        {
            Console.WriteLine("This is not specific data, sorry");
        }
    }
}

但是显示数据不是SpecificData。我猜它不起作用,因为SomeClass.Data 添加了new 关键字,所以specific 对象中有两个Data 属性。是否可以重写此代码以将基本非泛型类保存为Process(SomeClass someClass) 方法的参数,并通过一些修改保存类结构的其余部分但使其可行?也许我可以在Process 方法中找到所需的Data? 谢谢!

【问题讨论】:

  • "我猜它不起作用,因为 SomeClass.Data 添加了 new 关键字,因此特定对象中有两个 Data 属性。" -- 正确
  • @canton7,是否可以使用接口而不是基类来实现相同的行为?这样我会将ISomeClass 传递给Process() 方法?

标签: c# generics inheritance


【解决方案1】:

您可以通过使用接口而不是基类来解决此问题,并使用显式接口实现来实现接口的属性:

public interface ISomeClass
{
    BaseData Data { get; }
    BaseInfo Info { get; }
}

public class SomeClass<TData, TInfo> : ISomeClass
    where TData : BaseData, new()
    where TInfo : BaseInfo, new()
{
    public TData Data { get; protected set; }
    BaseData ISomeClass.Data => Data;
        
    public TInfo Info { get; protected set; }
    BaseInfo ISomeClass.Info => Info;

    public SomeClass()
    {
        Data = new TData();
        Info = new TInfo();
    }
}

如果您使用的是 C# 9,您还可以使用返回类型协方差:

public abstract class BaseClass
{
    public abstract BaseData Data { get; }
    public abstract BaseInfo Info { get; }
}

public class SomeClass<TData, TInfo> : BaseClass
    where TData : BaseData, new()
    where TInfo : BaseInfo, new()
{
    public override TData Data { get; }
    public override TInfo Info { get; }

    public SomeClass()
    {
        Data = new TData();
        Info = new TInfo();
    }
}

请注意,我必须在 SomeClass getter-only 中创建属性,因为基本属性必须是 getter-only,并且您不能在覆盖中添加 set 访问器。

如果您确实需要在构造函数之外设置此属性,您可以执行以下操作:

public class SomeClass<TData, TInfo> : BaseClass
    where TData : BaseData, new()
    where TInfo : BaseInfo, new()
{
    protected TData MutableData { get; set; }
    public override TData Data => MutableData;
    
    protected TInfo MutableInfo { get; set; }
    public override TInfo Info => MutableInfo;

    public SomeClass()
    {
        MutableData = new TData();
        MutableInfo = new TInfo();
    }
}

【讨论】:

  • 谢谢!我没有使用 c# 9,所以我选择了第一个建议,它正在对我的代码进行一些修改
【解决方案2】:

你必须使用 SpecificClass

static void Process(SomeClass someClass)
{
    if (someClass is SpecificClass specificClass)
    {
        Console.WriteLine($"This is specific data {specificClass.Data.StartFrom}");
    }
    else
    {
        Console.WriteLine("This is not specific data, sorry");
    }
}

【讨论】:

  • 它的工作,但第二个答案更适合我的需要。对不起
猜你喜欢
  • 2019-08-12
  • 1970-01-01
  • 2020-03-14
  • 1970-01-01
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
  • 2012-09-09
相关资源
最近更新 更多