C#:重写属性并返回派生类型

C#:重写属性并返回派生类型,c#,overriding,C#,Overriding,假设我有一个属性为“Details”的类a,它返回一个类B的实例 public class A { public virtual B Details {get; set;} } 也就是说,我有一个从a继承的类Aext(a扩展)。 但是我希望Aext.Details返回类Bext(B扩展)的实例: 这将不会编译,因为类型Bext必须与从继承的类型匹配。 当然,我可以很容易地解决这个问题,只需将B作为Aext的详细信息返回 public class Aext { B Details

假设我有一个属性为“Details”的类a,它返回一个类B的实例

public class A
{
    public virtual B Details {get; set;}
}
也就是说,我有一个从a继承的类Aext(a扩展)。 但是我希望Aext.Details返回类Bext(B扩展)的实例:

这将不会编译,因为类型Bext必须与从继承的类型匹配。
当然,我可以很容易地解决这个问题,只需将B作为Aext的详细信息返回

public class Aext
{
    B Details {get; set;}
}
分配将起作用,但每次使用Aext实例时,我都必须检查详细信息是Bext还是B

你认为有没有一种方法可以做比这个解决方案更干净的事情


谢谢。

没有-但我认为这表明基类在设计上有缺陷。您试图将接口行为强制到抽象类/方法上。基本方法什么都不做,到底继承了什么?基类可以有一个类型为B的受保护成员,由每个继承器访问,并通过它们自己的强类型访问器方法公开。所有继承者都可以使用该值,但使用者需要获取/设置数据的强类型版本。

也许您可以尝试使用泛型,如下所示:

public class A<T> where T : B
{
    public T Details { get; set; }
}

public class Aext : A<Bext>
{
}

public class B
{

}

public class Bext : B
{

}
public class B
{ }

public class Bext : B
{ }

public class A
{
    public virtual B Details { get; set; }

    public A()
    {
        Details = new B();
    }

}

public class Aext : A
{
    public override B Details => new Bext();
}
public interface IB
{ }
public class B : IB
{ }

public class Bext : IB
{ }

public class A
{
    public virtual IB Details { get; set; }

    public A(IB details)
    {
        Details = details;
    }
}

public class TestClass
{
    public void TestMethod()
    {
        IB details = new B();
        IB extDetails = new Bext();

        A instance1 = new A(details);
        A instance2 = new A(extDetails);
    }
}
公共A类,其中T:B
{
公共T详细信息{get;set;}
}
公共类Aext:A
{
}
公共B级
{
}
公共类文本:B
{
}

如果需要,您可以使用Bext Details覆盖T Details,它将正常工作。

如果您不想引入接口,可以执行以下操作:

public class A<T> where T : B
{
    public T Details { get; set; }
}

public class Aext : A<Bext>
{
}

public class B
{

}

public class Bext : B
{

}
public class B
{ }

public class Bext : B
{ }

public class A
{
    public virtual B Details { get; set; }

    public A()
    {
        Details = new B();
    }

}

public class Aext : A
{
    public override B Details => new Bext();
}
public interface IB
{ }
public class B : IB
{ }

public class Bext : IB
{ }

public class A
{
    public virtual IB Details { get; set; }

    public A(IB details)
    {
        Details = details;
    }
}

public class TestClass
{
    public void TestMethod()
    {
        IB details = new B();
        IB extDetails = new Bext();

        A instance1 = new A(details);
        A instance2 = new A(extDetails);
    }
}
但是,我建议您使用组合并使用依赖项注入,如下所示:

public class A<T> where T : B
{
    public T Details { get; set; }
}

public class Aext : A<Bext>
{
}

public class B
{

}

public class Bext : B
{

}
public class B
{ }

public class Bext : B
{ }

public class A
{
    public virtual B Details { get; set; }

    public A()
    {
        Details = new B();
    }

}

public class Aext : A
{
    public override B Details => new Bext();
}
public interface IB
{ }
public class B : IB
{ }

public class Bext : IB
{ }

public class A
{
    public virtual IB Details { get; set; }

    public A(IB details)
    {
        Details = details;
    }
}

public class TestClass
{
    public void TestMethod()
    {
        IB details = new B();
        IB extDetails = new Bext();

        A instance1 = new A(details);
        A instance2 = new A(extDetails);
    }
}

这样,您就不需要通过创建Aext类来扩展继承层次结构。你可以将其严格地包含在相关属性中。

B是抽象类吗?@Hadi Hassan:不,B不是抽象类。我不知道你在追求什么样的设计,但你面临的问题是,C不支持(非接口)虚拟方法中的协变返回类型。因此,您可以声明一个通用接口,使用
Details
返回值作为其通用类型参数,将其标记为协变,并且能够使用它并分配它,而不必知道确切的返回类型。我认为,这是实现它的最干净的方法。