C#使用具有“类类型”返回类型的另一个函数覆盖抽象类的函数

时间:2013-05-10 22:50:03

标签: c# class types virtual abstract

我正在尝试创建一个基于抽象类的类,并使用另一个返回类型为“T”的类覆盖基类中包含的函数,该类是由类传递的类型。

e.g:

public abstract class DayInfo
{
    public virtual void GetInfo()
    {
        throw new NotImplementedException();
    }
}

public class DayInfo<T> : DayInfo
{
    private T info;
    public DayInfo(T data)
    {
        info = data;
    }

    public T GetInfo() // << This
    {
        return info;
    }
}

示例:

1

DayInfo info = new DayInfo<String>("Blah");
String stuff = info.GetInfo();

2

DayInfo info = new DayInfo<int>(25);
int stuff = info.GetInfo();

以任何方式来实现这一目标吗?

编辑1: 我忘了确切地说我没有在基类中使用类传递类型,因为我希望能够将它用作泛型类型,而不必定义任何类型。

例如:

public SortedDictionary<int, DayInfo> Data = new SortedDictionary<int, DayInfo>();

编辑2:

此外,基类中虚函数的要点是,如果访问GetInfo()函数但未被覆盖,它将使子类抛出异常。

6 个答案:

答案 0 :(得分:1)

这是实现目标的方法:

public abstract class DayInfoA<T>
{
    public virtual T GetInfo()
    {
        .......
    }
}

public class DayInfoB<T> : DayInfoA<T>
{
    private T info;
    public DayInfoB(T data)
    {
        info = data;
    }

    public override T GetInfo() // << This
    {
      .........
    }
}

并像这样使用它:

        DayInfoB<int> info = new DayInfoB<int>(25);
        int stuff = info.GetInfo();

答案 1 :(得分:1)

为什么不将GetInfo()声明为dynamic? 这样铸造应该是自动的。唯一的缺点是您丢失了编译器断言,如果存储GetInfo()值的变量无法执行强制转换,则会抛出运行时错误。

例如:

public abstract class DayInfo {
    public abstract dynamic GetInfo();
}

public class DayInfo<T> : DayInfo {
    private readonly T _info;
    public DayInfo(T info) {
        _info = info;
    }
    public override dynamic GetInfo() {
        return _info;
    }
}

你也可以声明类似GetInfo<T>(ref T result)的东西,这样你可以省略方法调用中的T类型,让编译器在运行时推断它,唯一的缺点就是你应该传递变量将结果存储为参数,而不是通过方法返回它。

答案 2 :(得分:0)

不,不像它看起来像你想要它(假设你不想或不能改变基类声明)。为了使函数解析为多态调用,您需要具有相同的签名和返回类型。否则它不会以多态方式解析函数,它只会调用函数的基类版本,因为它看到你调用它(并且你为实例分配的变量属于基类类型)。

你可以做到这一点,但这很难看:

        DayInfo info = new DayInfo<String>("Blah");
        String stuff = ((DayInfo<string>)info).GetInfo();

答案 3 :(得分:0)

不,因为这些功能与不同的功能签名不匹配。

你能做的就是这样定义:

public abstract class DayInfo
{
    public virtual object GetInfo()
    {
        throw new NotImplementedException();
    }
}

并在派生类中这样:

public object GetInfo() // << This
{
    return info;
}

然后它们都具有相同的签名,并且多态性将匹配。 但是,另一方面需要演员阵容:

DayInfo info = new DayInfo<int>(25);
int stuff = (int)info.GetInfo();

编辑:除非有更多内容,否则我会把它变成一个界面,或者如果GetInfo确实没有做任何事情,那么GetInfo纯粹是抽象的。

public abstract object GetInfo();

答案 4 :(得分:0)

这可以使用NVI pattern生成:

public abstract class DayInfo
{
  protected virtual void GetInfoCore() {
    throw new NotImplementedException();
  }

  // or
  // protected abstract void GetInfoCore();

  public void GetInfo() {
    GetInfoCore();
  }
}

public class DayInfo<T> : DayInfo
{
  private T info;

  public DayInfo(T data) {
    info = data;
  }

  public new T GetInfo() { // << This
    return info;
  }

  protected override void GetInfoCore() {
    GetInfo();
  }
}

答案 5 :(得分:0)

您可以创建一个协变接口,而不是基类:

void Main()
{
    IDayInfo dayInfo = new DayInfo<string>("hi!");
    object info = dayInfo.GetInfo(); //info == "hi!"
}
public interface IDayInfo
{
    object GetInfo();
}
public interface IDayInfo<out T> : IDayInfo
{
    new T GetInfo();
}

public class DayInfo<T> : IDayInfo<T>
{
    private T info;
    public DayInfo(T data)
    {
        info = data;
    }

    public T GetInfo()
    {
        return info;
    }
    object IDayInfo.GetInfo()
    {
        return this.GetInfo();
    }
}

(有关协方差/逆变的信息,请参阅Variance in Generic Interfaces

请注意object info(在Main中的第二行)与此示例中未经强制转换的情况一样精确。将DayInfo<string>对象存储在IDayInfo<object>变量/字段中后,就像我一样(并且您希望在字典中执行此操作),string的更强类型是一种感觉,被遗忘,没有演员就无法恢复。

更新:添加了IDayInfo界面。