简体   繁体   English

C# 更改子类中抽象属性的返回类型

[英]C# Changing Return Type of Abstract Property in Child Class

TLDR: Is there anyway to override an abstract property and change it's return type at the same time, just like you can do with concrete properties? TLDR:无论如何要覆盖抽象属性并同时更改它的返回类型,就像您可以使用具体属性一样? I know the direct answer is "no", but I'm wondering if there's any workaround that doesn't involve adding a second property.我知道直接的答案是“不”,但我想知道是否有任何不涉及添加第二个属性的解决方法。

Let's say I have this abstract class:假设我有这个抽象类:

public abstract class Item {
  public abstract string SerialNumber { get; }
  public string PartNumber => "34";
}

Let's say I want a Toy class that implements Item .假设我想要一个实现ItemToy类。 Let's also say for some reason I want the SerialNumber and PartNumber properties to both be int values in the child class even though they are strings on the base.假设出于某种原因,我希望SerialNumberPartNumber属性在子类中都是 int 值,即使它们是基类中的字符串。 See below:见下文:

public abstract class Toy {
  public override int SerialNumber => 5; //Doesn't compile obviously
  public new int PartNumber => int.ParseInt(base.PartNumber); //works fine, refines the type but keeps the value
}

I included PartNumber just to show that I understand how the new keyword is supposed to work.我包含PartNumber只是为了表明我了解new关键字应该如何工作。 That part works fine for me.那部分对我来说很好用。

My question is: Is there any way to both override AND refine the type of SerialNumber at the same time?我的问题是:有什么方法可以同时覆盖和优化SerialNumber的类型? I understand what I have above doesn't work, but I'm looking for a simple workaround.我知道我上面的内容不起作用,但我正在寻找一个简单的解决方法。 The goal is to NOT use an extra property (like SerialNumberInt or something) so that the Toy class's methods can refer to SerialNumber and get it as an int.目标是不使用额外的属性(如SerialNumberInt或其他东西),以便Toy类的方法可以引用SerialNumber并将其作为 int 获取。

Thanks!谢谢!

What you're trying to do is not possible.你试图做的事情是不可能的。

The reason for this is that your base class expresses a contract, part of which is the return type of methods it exposes.这样做的原因是你的基类表达了一个契约,其中一部分是它公开的方法的返回类型。

Your subclass cannot fulfill this contract: suppose you have a class "ItemSubmitter", which has a method "submitItem", which internally does:你的子类不能履行这个契约:假设你有一个类“ItemSubmitter”,它有一个方法“submitItem”,它在内部执行:

   string partNumberToSubmit = item.PartNumber;

Since item.PartNumber in your example returns an int, this would cause an exception.由于您的示例中的 item.PartNumber 返回一个 int,这将导致异常。 How would you expect the compiler to deal with this situation?您希望编译器如何处理这种情况?

So, it is not possible.所以,这是不可能的。 This concept is generalized as the Liskov Substitution Principle from Barbara Liskov, see eg https://en.wikipedia.org/wiki/Liskov_substitution_principle .这个概念被概括为 Barbara Liskov 的 Liskov Substitution Principle,参见例如https://en.wikipedia.org/wiki/Liskov_substitution_principle

You could use generics, but this would require all base class consumers to also be generic.您可以使用泛型,但这将要求所有基类使用者也是泛型的。 In this case I'd question if you need a base class at all and simply make the consumers generic.在这种情况下,我会质疑您是否需要一个基类并简单地使消费者通用。

See also C# Override abstract property with concrete property另请参见C# 用具体属性覆盖抽象属性

It appears you've answered your own question (stated differently) some time ago: https://stackoverflow.com/a/40657803/11389043看来您前段时间已经回答了您自己的问题(以不同方式表述): https : //stackoverflow.com/a/40657803/11389043

This can be done using Generics.这可以使用泛型来完成。 But before you do it you need to be sure you are approaching your problem correctly.但在你这样做之前,你需要确保你正确地解决了你的问题。 That said, I've used the below idea to map domain entities with common properties but they have different Type s for their entity id.也就是说,我使用下面的想法来映射具有公共属性的域实体,但它们的实体 id 具有不同的Type

public abstract class ItemBase<TId>
{
    protected ItemBase(TId id)
    {
        ItemId = id;
    }
    public TId ItemId { get; }

}

public class Toy : ItemBase<int>
{
    public Toy(int id) : base(id)
    {

    }
}

public class NotAToy : ItemBase<Guid>
{
    public NotAToy(Guid id) : base(id)
    {

    }
}

You can do that using generics (see below) or you could just make everything an object.你可以使用泛型来做到这一点(见下文),或者你可以让一切都成为一个对象。 However, this really doesn't feel like a great solution but I don't know the purpose behind arbitrarily changing the types in this case.然而,这真的不是一个很好的解决方案,但我不知道在这种情况下任意改变类型背后的目的。

public abstract class Item <T,V>
{
    public abstract T SerialNumber { get; }
    public V PartNumber { get; }
}

public abstract class Toy : Item<int, int>
{
    public override int SerialNumber => 5; 
    public new int PartNumber => int.Parse(base.PartNumber.ToString()); 
}
public abstract class ToyString : Item<string, string>
{
    public override string SerialNumber => "3";
    public new string PartNumber => "34";
}

You can use generics to achieve this as follows:您可以使用泛型来实现这一点,如下所示:

public abstract class Item<T> {
  public abstract T SerialNumber { get; }
}
public  class Toy : Item<int> {
  public override int SerialNumber => 5;
}

However, you shouldn't necessarily do this.但是,您不一定要这样做。 You may want to confirm if this design is appropriate in your case since if you are redefining types on derived classes then it's most likely a problem with how you are defining your base class.您可能想确认这种设计是否适合您的情况,因为如果您在派生类上重新定义类型,那么很可能是您定义基类的方式有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM