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

时间:2010-08-23 19:32:42

标签: c# inheritance override 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.

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

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

//Now try use the result:
EarthSun.Cache[0]...

非常类似于此但使用派生类型而不是字符串数组: C# Member variable overrides used by base class method

这个答案对我来说没有多大意义: How to override member of base class after inheritance in C++

或许这意味着它不可能? Can I Override with derived types?

帮助! :)有任何解决方法吗?

5 个答案:

答案 0 :(得分:11)

确切地说,你想要它的方式是不可能的。

您可以使用相同名称创建“新”属性:

public new SunData Data
{
  get { return (SunData) base.Data; }
  set { base.Data = value; }
}

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

另一种可能的方法是:

public SunData SunData { get; set; }

public override OuterSpaceData Data
{
  get { return SunData; }
  set { SunData = (SunData)value; }
}

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

有一种丑陋的方式可以获得“两全其美”,代价是对代码造成混淆并且之后难以理解 - 通过引入一个中间派生类,对基类Data属性执行'密封覆盖',使用新名称重定向到不同的受保护属性,然后让最终派生类添加一个“new”Data属性,然后调用中间属性。不过,这真的是一个丑陋的黑客,即使我已经完成了,我也不会推荐它。

答案 1 :(得分: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 { }

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

答案 2 :(得分:1)

如果您正在寻找协方差路线,那么这样的事情应该有效:

public class OuterSpace<TCacheType> where TCacheType : OuterSpaceCache {
    public virtual OuterSpaceData Data {get; set;}
    public virtual OuterSpaceAnalysis Analysis {get; set;}
    public virtual TCacheType 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<SunCache> {
    public override SunData Data {get; set;}
    public override SunAnalysis Analysis {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;
    }
}

公平警告,完全未编译的代码,我可能完全错了:)但这是我想你想要的......

哦,我认为这是一个.Net 4.0唯一的解决方案,我认为你不能早点做到这一点,那里引入了协方差......

答案 3 :(得分:0)

如果SunData与Outerspace Data兼容(继承自),那么您不需要修改OuterSpaceData的类型

答案 4 :(得分:0)

不确定Generics,但是你可以用简单的多态性实现有限的效果(假设SunData继承自Data等)

public class Sun : OuterSpace 
{
  void SomeInitializationMethod()
  {
    Data = new SunData();
    Analysis = new SunAnalysis(); // etc
  }

    }

// You could also make casting simpler with a generic method on the base
public T GetData<T>()
{
  if (Data is T)
  {
    return Data as T;
  }
  return null;
};