从AbstractClass <t>调用AbstractClass实例的方法

时间:2017-10-09 13:29:29

标签: c# .net generics

假设我有一个抽象类,如:

abstract class MyAbstractClass
{
    public object GetValue(object parameter)
    {
        Console.WriteLine("Hello from object");
        return parameter;
    }
}

另外,我还有另一个扩展MyAbstractClass的抽象类:

abstract class MyAbstractClass<T> : MyAbstractClass
{
    public T GetValue(T parameter)
    {
        Console.WriteLine("Hello from generics");
        return parameter;
    }
}

使用string作为泛型类型参数的简单具体类:

class MyImpClass : MyAbstractClass<string> { }

现在,我正在声明MyAbstractClass列表(没有通用类型),添加MyImpClass的实例并调用您的GetValue方法。

public static void Main(string[] args)
{
    IList<MyAbstractClass> list = new List<MyAbstractClass>();
    list.Add(new MyImpClass());
    list[0].GetValue("Testing...");
}

目前调用来自MyAbstractClass的方法(没有通用类型参数)并打印出"Hello from object"

如果我直接从MyImpClass的实例调用该方法,则会调用来自MyAbstractClass<T>的方法。

new MyImpClass().GetValue("Testing...");

我这样做是因为在我的应用程序的某些部分,无论泛型类型参数如何,我都需要接收MyAbstractClass<T>的实例。所以我使用MyAbstractClass这样做。

我的问题是:有没有办法从MyAbstractClass<T>调用MyAbstractClass列表来调用方法?

我希望我已经足够清楚了。感谢。

4 个答案:

答案 0 :(得分:4)

要直接调用泛型调用,您需要将其强制转换:

(list[0] as MyAbstractClass<string>)?.GetValue("Testing...");

但在我看来,这不是一个好的解决方案,你应该采取以下措施:

  • 在您的通用类中覆盖非通用基类的GetValue 并在其中调用通用GetValue

    abstract class MyAbstractClass<T> : MyAbstractClass
    {
        public T GetValue(T parameter)
        {
            Console.WriteLine("Hello from generics");
            return parameter;
        }
    
        public override object GetValue(object parameter)
        {
            return GetValue((T)parameter);
        }
    }
    
  • 或者,since C# 6.0,您也可以这样写:

    public override object GetValue(object parameter) => GetValue((T)parameter);
    

您还需要将MyAbstractClass的方法更改为虚拟:

public virtual object GetValue(object parameter)

答案 1 :(得分:3)

制作public object GetValue(object parameter) virtual,并在通用版本中覆盖它。

像这样:

abstract class MyAbstractClass
{
    public virtual object GetValue(object parameter)
    {
        Console.WriteLine("Hello from object");
        return parameter;
    }
}

abstract class MyAbstractClass<T> : MyAbstractClass
{
    override public object GetValue(object parameter)
    {
        return GetValue((T)parameter);
    }

    public T GetValue(T parameter)
    {
        Console.WriteLine("Hello from generics");
        return parameter;
    }
}

class MyImpClass : MyAbstractClass<string> { }

此代码:

void Main()
{
        IList<MyAbstractClass> list = new List<MyAbstractClass>();
        list.Add(new MyImpClass());
        list[0].GetValue("Testing...");
}

现在生成以下输出:

  

来自仿制药的你好

我不确定有些人认为这没有回答这个问题。

如果从所有类中删除abstract修饰符,请使用以下代码:

IList<MyAbstractClass> list = new List<MyAbstractClass>();
list.Add(new MyAbstractClass());
list.Add(new MyImpClass());
foreach (var item in list)
{
    item.GetValue("Testing...");
}

它产生这个输出:

  

来自对象的你好   您好,来自仿制药

这似乎是OP最终希望代码执行的操作;迭代基类型的集合,如果实例是通用的,则调用泛型方法。

具体地将问题解释为要求方法的泛型版本是直接调用的方法,似乎忽略了我的X / Y问题。

答案 2 :(得分:2)

以这种方式无法实现您想要实现的目标。这将要求您覆盖方法,但您要做的是添加第二个方法,称为重载

根据规范,您既不能更改方法的返回类型,也不能更改参数类型。其他语言支持所谓的共变量返回类型或反变量参数类型,但C#不支持。

您可以做的是使用接口和显式实现:

interface IInterface
{
    object GetValue(object parameter);
}

abstract class MyAbstractClass<T> : IInterface where T : class
{
    public T GetValue(T parameter)
    {
        // ...
    }

    object IInterface.GetValue(object parameter) => GetValue(parameter as T);
}

...然后使用界面:

public static void Main(string[] args)
{
    IList<IInterface> list = new List<IInterface>();
    list.Add(new MyImpClass());
    list[0].GetValue("Testing...");
}

答案 3 :(得分:1)

只需将您的基本方法设为虚拟并在泛型类中覆盖它。

  abstract class MyAbstractClass
    {
        public virtual object GetValue(object parameter)
        {
            Console.WriteLine("Hello from object");
            return parameter;
        }
    }

abstract class MyAbstractClass<T> : MyAbstractClass
{
 public override object GetValue(object parameter)
    {
        return GetValue((T)parameter);
    }
    public T GetValue(T parameter)
    {
        Console.WriteLine("Hello from generics");
        return parameter;
    }
}