【问题标题】:Inheriting generic abstract继承通用抽象
【发布时间】:2016-01-07 03:49:53
【问题描述】:

我不确定这是否可能,希望得到一些澄清。

我有一个这样的类结构:

public class FooBase
{
    //Some base class
}

public class BarBase
{
    //Some base class    
}

public class Foo : FooBase
{
    //Implementation
}

public class Bar : BarBase
{
    //Implementation
}

public abstract class FooBarHolderAbstract<T, V> where T: FooBase where V: BarBase
{
}

public class MyFooBarHolderImpl : FooBarHolderAbstract<Foo, Bar>
{
}

public class FooBarTest
{
    public void DoSomethingWithFooBar<T>() where T : FooBarHolderAbstract<FooBase, BarBase>
    {
        //Do something tith the obj
    }

    public void RunTest()
    {
        //This doesn't work, compiler says MyFooBarHolder is not convertible to FooBarHolderAbstract<FooBase, BarBase>
        DoSomethingWithFooBar<MyFooBarHolderImpl>();
    }
}

在 FooBarTest 类中,我想创建一个接受泛型参数的方法,该方法继承自具有两个泛型参数的抽象类。 MyFooBarHolderImpl 类扩展了抽象基类,并使用继承自抽象类的泛型参数类型的类型指定其泛型参数。

当我尝试调用此方法 (DoSomethingWithFooBar()) 时,编译器告诉我 MyFooBarHolderImpl 类型必须可转换为 FooBarHolderAbstract

这是根本无法完成的事情,还是我缺少概念/语法?

提前致谢!

【问题讨论】:

  • @thebigbo:你在两个方面都错了。也许您正在考虑另一种语言?
  • 大哥,你在这两个方面都错了,这不是 c++
  • 是的。对困惑感到抱歉。我以为是c++

标签: c# .net generics inheritance abstract


【解决方案1】:

不清楚,你要在DoSomethingWithFooBar做什么,因为你没有传递任何参数,但这里有另一种选择:

public class FooBarTest
{
    public void DoSomethingWithFooBar<TFooBase, TBarBase>(FooBarHolderAbstract<TFooBase, TBarBase> obj) 
        where TFooBase : FooBase
        where TBarBase : BarBase
    {
        //Do something tith the obj
    }

    public void RunTest()
    {
        DoSomethingWithFooBar<Foo, Bar>(new MyFooBarHolderImpl());
    }
}

public class FooBarTest
{
    public void DoSomethingWithFooBar<TFooBase, TBarBase, THolder>() 
        where TFooBase : FooBase
        where TBarBase : BarBase
        where THolder : FooBarHolderAbstract<TFooBase, TBarBase>
    {
        //Do something tith the obj
    }

    public void RunTest()
    {
        DoSomethingWithFooBar<Foo, Bar, MyFooBarHolderImpl>();
    }
}

【讨论】:

  • 第一个版本对我不起作用,因为在我想传入通用参数的时候,我没有它的实例。第二个版本有效,但是这样我在调用 DoSomethingWithFooBar 时必须冗余指定 TFooBase 和 TBarBase,我想避免这种情况,因为我认为 MyFooBarHolderImpl 已经“知道” FooBase 和 BarBase 的哪个子级是它实现 FooBarHolderAbstract 的。此外,在现实生活场景中,我实际上有 FooBarHolderAbstract 的三个通用参数,所以这最终有点难看。无论如何,谢谢!
【解决方案2】:

你必须写你的FooBarTest 如下。您必须将TDoSomethingWithFooBar&lt;T&gt; 定义为FooBarHolderAbstract&lt;Foo, Bar&gt;

    public class FooBarTest
    {
        public void DoSomethingWithFooBar<T>() where T : FooBarHolderAbstract<Foo, Bar>
        {
            //Do something tith the obj
        }

        public void RunTest()
        {                         
            DoSomethingWithFooBar<MyFooBarHolderImpl>();
        }
    }

【讨论】:

  • 这可以工作,但我失去了以这种方式设计它的要点。我想用泛型调用 DoSomethingWithFooBar,它的泛型参数不同于 Foo 和 Bar,但继承自 FooBase 和 BarBase。
【解决方案3】:

好吧,它不能直接完成 - FooBarHolderAbstract&lt;Foo, Bar&gt; 不是 FooBarHolderAbstract&lt;FooBase, BarBase&gt;。目前尚不清楚您是否可以在逻辑上拥有它,因为我们不知道抽象类中有什么。

您基本上是在寻找generic covariance,但无论如何类都不支持 - 所以您可能想要引入一个接口:

public interface IFooBarHolder<out T, out V>
    where T: FooBase
    where V: BarBase
{
    // Define what you need in here
}

public abstract class FooBarHolderAbstract<T, V> : IFooBarHolder<T, V>
    where T : FooBase
    where V : BarBase
{

}

此时,您可以将FooBarTest 更改为:

public void DoSomethingWithFooBar<T>() where T : IFooBarHolder<FooBase, BarBase>
{
    //Do something with the obj
}

...因为IFooBarHolder&lt;Foo, Bar&gt; IFooBarHolder&lt;FooBase, BarBase&gt;

但是,这仅在您可以为在“out”位置使用TV 的接口定义所有操作时才有效,例如从方法返回类型。如果您需要它们在“输入”位置,例如作为方法参数,你被卡住了——因为期望 Foo 的方法无法处理任何其他类型的 FooBase

【讨论】:

  • 不幸的是,在我的情况下,我需要在 IFooBarHolder 的某些方法中输入位置的泛型,所以像 void DoSomething(V param, int value);所以我不能将它们指定为“出”位置,因此我被卡住了。无论如何,我会找到一种不同的方法,感谢您指出这一点,它有很大帮助!
  • @AttilaBicskó:另一种选择是为 DoSomethingWithFooBar 指定两个类型参数 - T 和 V。很难知道这是否会对您有所帮助。
  • 是的,我正在尝试,这就是@Dennis 在下面指出的,但这对我没有帮助,我试图避免重复指定泛型参数的需要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多