【问题标题】:Change parameter type when implementing an abstract method实现抽象方法时更改参数类型
【发布时间】:2023-03-22 23:22:01
【问题描述】:

有没有办法将抽象类型定义为抽象方法中的参数,并且当该方法在派生类中实现时,您将方法的类型更改为接受派生类型?

代码:

public abstract class ProductBase
{
}

public class SomeProduct
    : ProductBase
{

}

public abstract class A
{
    protected abstract void addProduct(ProductBase p);
}

// This works
public class B : A
{        
    protected override void addProduct(ProductBase p)
    {
        // Do some work
    }
}

// This is what I'd like to do
public class C : A
{
    // Compiler error here because I have accepted a SomeProduct and not a ProductBase
    protected override void addProduct(SomeProduct p)
    {
        // Do some work on the specialisation - I can use the SomeProduct directly
    }
}

在我的脑海中,它有某种意义。一个抽象类,表示派生类必须实现一个方法,但是它们可以改变作为参数传入的对象的类型,只要它来自同一个继承链......

我最终做的是从抽象类中删除抽象方法AddProduct,而只是在派生类中实现它,但是将来他们必须创建的其他类没有合同他们自己实现AddProduct。而且它感觉不对

我希望这是有道理的。抱歉,如果这是一个重复的问题,但我无法通过搜索找到任何内容。

谢谢,
bgs264

【问题讨论】:

    标签: c# inheritance abstract-class


    【解决方案1】:

    不,这是不可能的:假设您在类 A 的变量上调用 addProduct,该变量指向类 C 的实例,传递的对象是 ProductBase,但不是 @ 987654325@。传递的实例无法转换为SomeProduct,这就是为什么这首先不会编译。

    最接近这个的是泛型解决方案:

    public abstract class A<T>
        where T : ProductBase
    {
        protected abstract void addProduct(T p);
    
    }
    

    然后,您可以像这样定义您的 C 类:

    public class C : A<SomeProduct>
    {
        protected override void addProduct(SomeProduct p);
    }
    

    当然,这意味着您必须将A 类型的任何变量键入到SomeProduct,如A&lt;SomeProduct&gt; = new C();

    如果不指定 T 类型参数的实际值,就不能再只有一个 A 类型的变量(提供 addProduct 方法)。另一方面,如上所述,在您的解决方案中也无法调用 addProduct 方法。

    您现在可能引入一个非强类型方法:

    public abstract class A<T>
        where T : ProductBase
    {
        protected abstract void addProduct(T p);
    
        protected void addProductUntyped(ProductBase p)
        {
            T typedProduct = p as ProductBase;
            if (typedProduct != null) {
                addProduct(typedProduct);
            } else {
                throw new ArgumentException("p has an incompatible type.");
            }
        }
    }
    

    但是,这种解决方案通常只有在类的某些用户可以知道泛型类型而其他用户不知道的情况下才真正需要。

    【讨论】:

      【解决方案2】:

      您可以将您的 A 类设为泛型并在您的 addProduct 方法中使用泛型参数:

      public abstract class A<TProduct> where TProduct : ProductBase 
      {
          protected abstract void addProduct(TProduct p);
      }
      
      public class B : A<ProductBase>
      {        
          protected override void addProduct(ProductBase p)
          {
          }
      }
      
      public class C : A<SomeProduct>
      {
          protected override void addProduct(SomeProduct p)
          {
          }
      }
      

      【讨论】:

      • @bgs264 注意:这样做的一个大问题是你失去了A 的抽象。例如,您不能拥有List&lt;A&gt;,或A a = SomeFactoryMethod();
      • @bgs264:这样做时,请确保您确实想要/需要抽象类。你现在无论如何都不能调用addProduct而不指定TProduct,即使你只想拥有一个A类型的变量。参看。我对这个问题的解决方案中的评论。
      • 感谢两位 cmets,将把他们都考虑在内,对我来说有点学习曲线! :)
      【解决方案3】:

      坦率地说,对于 实现 代码,我只需要一个演员表。我唯一一次让这个“漂亮”是如果它影响了公众来电者:

      protected override void addProduct(ProductBase p)
      {
          SomeProduct prod = (SomeProduct)p;
          // ...
      }
      

      我自己非常喜欢的一个选项是泛型:

      public abstract class A<T> where T : ProductBase
      {
          protected abstract void addProduct(T p);
      }
      
      public class C : A<SomeProduct>
      {
          protected override void addProduct(SomeProduct p)
          {
              // ...
          }
      }
      

      我不喜欢这个的原因是你不能再使用非泛型的A,所以你失去了很多抽象。另一种选择是通过new 方法重新声明参数。不幸的是,您不能将newoverride 置于同一级别,但解决方法是使用两种方法:

      public abstract class A
      {
          protected void addProduct(ProductBase p) { addProductImpl(p);}
          protected abstract void addProductImpl(ProductBase p);
      }
      
      public class C : A
      {
          new protected void addProduct(SomeProduct p) { addProductImpl(p);}
          protected override void addProductImpl(ProductBase p)
          {
              SomeProduct prod = (SomeProduct) p;
              // ...
          }
      }
      

      【讨论】:

      • 感谢您的回答和解释,我很感激。我要走泛型路线。我理解你的意思,但我更喜欢类型安全,即 C 的实例只能将 SomeProduct 传递给 addProduct,而不是恰好继承 ProductBase 的不同类型。但再次感谢。 =)
      猜你喜欢
      • 1970-01-01
      • 2013-05-30
      • 1970-01-01
      • 1970-01-01
      • 2021-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多