使用派生类型和相同名称覆盖属性C#

Jar*_*oad 10 c# inheritance overriding covariance

我正在尝试使用具有相同名称的不同但派生类型覆盖基类中的属性.我认为它可以通过协变或泛型,但我不知道该怎么做?

以下代码获取错误:

错误1'Sun.Cache':类型必须是'OuterSpace.Cache'才能匹配被覆盖的成员'OuterSpace.Cache'

public class OuterSpace {
    public virtual OuterSpaceData Data {get; set;}
    public virtual OuterSpaceAnalysis Analysis {get; set;}
    public virtual OuterSpaceCache Cache {get; set;}


    public class OuterSpaceData {
        //Lots of basic Data Extraction routines eg
        public virtual GetData();
    }
    public class OuterSpaceAnalysis {
        //Lots of Generic Analysis on Data routines eg
        public virtual GetMean();
    }
    public class OuterSpaceCache {
        //Lots of Caches of Past Analysis Results:
        public Dictionary<AnalysisType, List<Result>> ResultCache;
    }
}

public class Sun : OuterSpace {
    public override SunData Data {get; set;}
    public override SunAnalysis Analysis {get; set;}
    public override SunCache Cache {get; set;}

    public SunData : OuterSpaceData {
        //Routines to specific get data from the sun eg
        public override GetData();
    }

    public SunAnalysis : OuterSpaceAnalysis {
        //Routines specific to analyse the sun: eg
        public double ReadTemperature();
    }
    public SunCache : OuterSpaceCache {
        //Any data cache's specific to Sun's Analysis
        public Dictionary<AnalysisType, List<Result>> TempCache;
    }
}

public class Moon : OuterSpace {} etc.
Run Code Online (Sandbox Code Playgroud)

对于最终结果,当我处理Sun的"数据"对象时,我不希望有两个数据对象(继承和基类),但是当我尝试覆盖该属性时,它要求Sun变量的类型与基类.例如:

Sun EarthSun = new Sun()
EarthSun.Analyse()  //The OuterSpace Analysis Saves results to Sun Cache:

//Now try use the result:
EarthSun.Cache[0]...
Run Code Online (Sandbox Code Playgroud)

与此非常相似,但使用派生类型而不是字符串数组: C#基类方法使用的成员变量覆盖

这个答案对我来说没有多大意义: 如何在C++中继承后覆盖基类的成员

或许这意味着它不可能? 我可以用派生类型覆盖吗?

救命!:)任何解决方法?

Stu*_*art 11

确切地说,这是不可能的.

您可以使用相同的名称创建"new"属性:

public new SunData Data
{
  get { return (SunData) base.Data; }
  set { base.Data = value; }
}
Run Code Online (Sandbox Code Playgroud)

这不是一回事,但它可能就像你要得到的那样接近.

另一种可能的方法是:

public SunData SunData { get; set; }

public override OuterSpaceData Data
{
  get { return SunData; }
  set { SunData = (SunData)value; }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是它确实可以保证在您的Data属性中放置一些不是SunData的东西.缺点是您的Data属性不是强类型的,如果您希望它静态地键入SunData,则必须使用SunData属性.

有一种丑陋的方式来获得"两全其美"的代价是以牺牲代码和后来难以理解为代价 - 通过引入一个中间派生类,在基类Data属性上执行'密封覆盖'并重定向到使用新名称的不同受保护属性,然后让最终派生类添加一个"新"数据属性,然后调用中间属性.不过,这真的是一个丑陋的黑客,即使我已经完成了,我也不会推荐它.


kbr*_*ton 7

尝试使用泛型.下面的类提供了一个通用基类,用于OuterSpace对其参数进行约束,从而对属性类型强制执行继承规则.为清楚起见,我省略了小类型的方法.

public class OuterSpace<TData, TAnalysis, TCache>
    where TData : OuterSpaceData
    where TAnalysis : OuterSpaceAnalysis
    where TCache : OuterSpaceCache
{
    public virtual TData Data { get; set; }
    public virtual TAnalysis Analysis { get; set; }
    public virtual TCache Cache { get; set; }
}
public class OuterSpaceData { }
public class OuterSpaceAnalysis { }
public class OuterSpaceCache { }

public class Sun : OuterSpace<SunData, SunAnalysis, SunCache>
{
    public override SunData Data { get; set; }
    public override SunAnalysis Analysis { get; set; }
    public override SunCache Cache { get; set; }
}
public class SunData : OuterSpaceData { }
public class SunAnalysis : OuterSpaceAnalysis { }
public class SunCache : OuterSpaceCache { }
Run Code Online (Sandbox Code Playgroud)

这种方法的吸引力在于它允许您返回强类型属性并对这些属性的类型强制执行基本继承约束.这些方法完全可以覆盖; 但是,请注意,可能需要覆盖以避免在基类实现中出现问题.