简体   繁体   English

在非通用类上重写通用方法

[英]Overriding a generic method on a non generic class

I know how to accomplish my goal when using a generic class. 我知道使用泛型类时如何实现我的目标。 But to understand why the syntax of generic methods is allowed (to be declared virtual or abstract) in a non-generic class I can't seem to determine. 但是要理解为什么非类中允许使用泛型方法的语法(被声明为虚拟或抽象),我似乎无法确定。

The first chunk of code shows a simple example using a generic class to create an abstract method that returns more specific interface than the one constrained in the base class. 第一部分代码显示了一个简单的示例,该示例使用泛型类创建一个抽象方法,该方法返回比基类中约束的接口更具体的接口。

public interface ISeries
{
    string Name { get; set; }
    string Color { get; set; }
}
public interface ITimeSeries<TY> : ISeries
{
    double[] XValues { get; set; }
    TY[] YValues { get; set; }
}

public interface IPhasorSeries : ISeries
{
    double Magnitude { get; }
    double Angle { get; }
}
public class PhasorSeries : IPhasorSeries
{
    public string Name { get; set; }
    public string Color { get; set; }
    public double Magnitude { get; set; }
    public double Angle { get; set; }
}
public class Series<T> : ITimeSeries<T>
{
    public string Name { get; set; }
    public string Color { get; set; }
    public double[] XValues { get; set; }
    public T[] YValues { get; set; }
}
public abstract class Chart<T> where T : ISeries
{
    public abstract T GetSeries();
}

public class AnalogChart : Chart<ISeries>
{
    public override ISeries GetSeries()
    {
        return new Series<float>();
    }
}

public class PhasorChart : Chart<IPhasorSeries>
{
    public override IPhasorSeries GetSeries()
    {
        return new PhasorSeries();
    }
}

Now, if remove the generic type from the Chart class but keep the generic method with the ISeries constraint I get errors on the following. 现在,如果从Chart类中删除泛型类型,但是将泛型方法保留在ISeries约束下,则会在以下内容中出错。

public abstract class Chart
{
    public abstract T GetSeries<T>() where T : ISeries;
}

public class AnalogChart : Chart
{
    public override T GetSeries<T>()
    {
        // ERROR:
        // Cannot implicitly convert type Test.Series<float> to 'T'
        // Cannot convert expression type Test.Series<float> to return type 'T'
        return new Series<float>();
    }
}

public class PhasorChart : Chart
{
    public override T GetSeries<T>()
    {
        // ERROR:
        // Cannot implicitly convert type Test.PhasorSeries to 'T'
        // Cannot convert expression type Test.PhasorSeries to return type 'T'
        return new PhasorSeries();
    }
}

It appears I don't fully understand what is going on when implementing a generic method in a non-generic class. 似乎我不完全理解在非泛型类中实现泛型方法时发生了什么。 When a generic class is used--there exist multiple class definitions. 使用泛型类时-存在多个类定义。 What does it mean when you only have a generic method? 当您只有通用方法时,这意味着什么? Are there actually multiple methods? 实际上有多种方法吗? or does it somehow just call the same method? 还是以某种方式调用相同的方法?

If this is essentially not supported with abstract and virtual keywords, I would have expected to get an error when creating an abstract generic method. 如果抽象和虚拟关键字基本不支持此功能,那么我会在创建抽象泛型方法时遇到错误。 How would one properly use an abstract generic method if you cannot use the syntax here to avoid casting in other code. 如果您不能在此处使用语法以避免转换其他代码,那么如何正确使用抽象泛型方法。 (I can't even cast the T to an ISeries-- it appears the constraint is lost in the subclass as if it doesn't know T must be an ISeries) (我什至无法将T强制转换为ISeries -似乎约束在子类中丢失了,就好像它不知道T必须是ISeries一样)

Note the purpose of the question here is to understand what is going on not to work around this problem or have different 'solutions' proposed. 请注意,这里提出问题的目的是要了解发生了什么,而不是解决此问题或提出不同的“解决方案”。

when your return type is T , you must return a T whatever T is. 当您的返回类型为T ,无论T是什么,都必须返回T You can't return an object with a hardcoded type and hope that It's a T. 您不能返回具有硬编码类型的对象,并希望它是T。

suppose you do the following code 假设您执行以下代码

Series<int> intSeries = angloChart.GetSeries<Series<int>>();

That would be valid code according to the signature of GetSeries , however, the method you wrote, if comparable, would put a Series<float> into a variable of type Series<int> That's why return new Series<float>(); 根据GetSeries的签名,这将是有效的代码,但是,您编写的方法(如果具有可比性)会将Series<float>放入Series<int>类型的变量中。这就是为什么要return new Series<float>();的原因return new Series<float>(); is not allowed in a method that returns a T 返回T的方法中不允许

When you use a generic method, it means that you do not know the concrete type of that T parameter. 使用泛型方法时,这意味着您不知道该T参数的具体类型。

So how can you decide that it is a Series<float> ? 那么,如何确定它是Series<float>呢?

What prevents me from calling this method like this: 是什么阻止我像这样调用此方法:

var ac = new AnalogChart();
Series<int> series = ac.GetSeries<Series<int>>();

This would lead to a casting error, since inside you are trying to return a Series<float> 这将导致转换错误,因为在内部您试图返回Series<float>

Your initial attempt with the generic classes seems like a better approach. 您最初尝试使用泛型类似乎是一种更好的方法。

By the way, you could "trick" the compiler and let it go through, but that is not a good idea, unless you are absolutely sure this would be the type of T (and even then i would choose a different strategy): 顺便说一句,您可以“欺骗”编译器并使其通过,但这不是一个好主意,除非您完全确定这将是T的类型(即使那样我也会选择其他策略):

return (T)(object) new Series<float>();

To achieve the desired result I realized that I could use an explicit interface implementation and avoid using generics all together. 为了获得理想的结果,我意识到我可以使用显式的接口实现,而避免同时使用泛型。

public interface IChart
{
    ISeries GetSeries();
}
public abtract class Chart : IChart
{
    public virtual ISeries GetSeries()
    {
        throw new NotImplementedException();
    }
}

public class AnalogChart : Chart, IChart
{
    public new ITimeSeries<float> GetSeries()
    {
        return new Series<float>();
    }

    ISeries IChart.GetSeries()
    {
        return GetSeries();
    }
}

public class PhasorChart : Chart, IChart
{
    public new IPhasorSeries GetSeries()
    {
        return new PhasorSeries();
    }
    ISeries IChart.GetSeries()
    {
        return GetSeries();
    }
}

This allows getting an ISeries if you have a Chart or IChart variable, but allows retrieving a more specific interface if you have a more concrete type. 如果您具有Chart或IChart变量,则可以获取ISeries;但是,如果您具有更具体的类型,则可以获取更具体的接口。 Unfortunately it looks like I can't override the abstract while making it new, so I'm stuck using a virtual method in the abstract class that throws. 不幸的是,看起来好像不能在抽象时覆盖它,所以我在抛出的抽象类中使用了虚方法。

I wanted to use the same method name, albeit I could have also just created 'GetPhasorSeries', 'GetTimeSeries' methods instead, but I really wanted to dig in and achieve this specific result. 我想使用相同的方法名称,尽管我也可以只创建“ GetPhasorSeries”,“ GetTimeSeries”方法,但我确实想深入研究并实现这一特定结果。

I was trying to bend generics in a way that they weren't designed. 我试图以非设计的方式改变通用名称。 Although I'm still not sure why you would ever create a generic method that is abstract or virtual. 尽管我仍然不确定为什么您会创建抽象或虚拟的通用方法。 I still would welcome any ideas about what pattern uses this construct (given all the context from this question). 我仍然欢迎有关使用哪种模式使用此构造的任何想法(考虑到该问题的所有上下文)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM