0

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

例如:

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() 函数被访问但未被覆盖,它将使子类抛出异常。

4

6 回答 6

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();
于 2013-05-10T22:56:38.447 回答
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从方法调用中省略类型,让编译器在运行时推断它,唯一的缺点是你应该传递变量来存储结果作为参数,而不是让它返回方法。

于 2013-05-10T23:30:11.150 回答
0

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

你可以这样做,但它非常难看:

        DayInfo info = new DayInfo<String>("Blah");
        String stuff = ((DayInfo<string>)info).GetInfo();
于 2013-05-10T23:00:38.757 回答
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();
于 2013-05-10T23:04:54.647 回答
0

这可以使用NVI 模式生成:

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();
  }
}
于 2013-05-10T23:13:37.743 回答
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();
    }
}

(有关协方差/逆变的信息,请参阅通用接口中的方差)

请注意,object info(在我的第二行中Main)在此示例中与不进行强制转换的情况一样精确。一旦您将DayInfo<string>对象存储在IDayInfo<object>变量/字段中,就像我所做的(以及您希望在字典中做的那样),从string某种意义上说,更强的类型是被遗忘的,并且在没有强制转换的情况下无法恢复。

更新:添加IDayInfo界面。

于 2013-05-10T23:15:36.603 回答