使用派生自通用抽象类的类的C#方法重载问题 [英] C# Method Overload Problem With Class Derived From Generic Abstract Class

查看:140
本文介绍了使用派生自通用抽象类的类的C#方法重载问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一个项目,并且我有一个通用的抽象类型,它接受一个从抽象类型派生的类型参数。如果你想知道我为什么要这样做,请参阅 this question



我在抽象类中定义的派生类中重载了一个方法时遇到了一个有趣的问题。这里是一个代码示例:

  public abstract class AbstractConverter< T,U> 
其中U:AbstractConvertible
其中T:AbstractConverter< T,U>
{
public abstract T Convert(U convertible);
}

public class DerivedConvertibleConverter:AbstractConverter< DerivedConvertibleConverter,DerivedConvertible>
{
public DerivedConvertibleConverter(DerivedConvertible convertible)
{
Convert(convertible);
}

public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
{
//这不会被称为
System.Console.WriteLine(Called the大多数派生方法);
返回此;


public DerivedConvertibleConverter Convert(Convertible convertible)
{
System.Console.WriteLine(调用最小派生方法);
返回此;



public abstract class AbstractConvertible {}

public class Convertible:AbstractConvertible {}

public class DerivedConvertible :Convertible {}

在上面的示例中,抽象父项中不存在的Convert的重载(并且派生得更少)被调用。我期望从父类中派生出最多的版本。



为了解决这个问题,我遇到了一个有趣的解决方案:

  public abstract class AbstractConverter< U> 
其中U:AbstractConvertible
{
public abstract AbstractConverter< U>转换(U convertible);
}

public class DerivedConvertibleConverter:AbstractConverter< DerivedConvertible>
{
public DerivedConvertibleConverter(DerivedConvertible convertible)
{
Convert(convertible);
}

public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
{
System.Console.WriteLine(Called the most derived method);
返回此;


public DerivedConvertibleConverter Convert(Convertible convertible)
{
System.Console.WriteLine(调用最小派生方法);
返回此;



public abstract class AbstractConvertible {}

public class Convertible:AbstractConvertible {}

public class DerivedConvertible :Convertible {}

当派生类型参数从基类中移除时,转换被称为。我不希望这种差异,因为我不希望Convert的抽象版本的界面发生了变化。但是,我一定是错的。任何人都可以解释为什么发生这种差异?

解决方案


在上面的示例中,Convert的重载不存在于抽象父(并且派生较少)被调用。我期望从父类中派生出来的最大版本将被称为

许多人都有这种期望。然而,你观察到的行为是正确的和设计的。



重载解析算法就像这样。首先,我们列出您可能调用的所有可能的可访问方法的列表。 覆盖虚拟方法的方法被认为是声明它们的类的方法,而不是覆盖它们的类。然后我们过滤掉参数不能转换为正式参数类型的方法。然后,我们筛选出任何类型少于派生的所有方法,而不是具有适用方法的任何类型。然后,我们确定哪种方法比另一种方法更好,如果还有多余的方法。



在您的情况下,有两种可能的适用方法。采用DerivedConvertible的方法被认为是基类的方法,因此不如采用Convertible的方法。

这里的原则是覆盖虚拟方法是一个可能会改变的实现细节,而不是暗示编译器会选择重载方法。更一般地说,重载解析算法的这些特性旨在帮助缓解脆弱基类问题的各种版本。




$ b

有关这些设计决策的更多详细信息,请参阅我的文章: .COM / b / ericlippert /存档/ 2007/09/04 /未来的磨合变化 - 部分 - three.aspx> http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/ future-breaking-changes-part-three.aspx


当派生类型参数从基类中移除时,调用大多数派生版的Convert。我不希望这种差异,因为我不希望Convert的抽象版本的界面发生了变化。


问题是基于错误的前提;最派生的版本是 not 调用。程序片断是错误的,因此不能编译,因此这两种方法都不会被调用;该程序不运行,因为它不能编译。


I am working on a project, and I have a generic abstract type that takes a type parameter that is itself derived from the abstract type. If you want to know why I would do this, please see this question.

I have run into an interesting problem with overloading a method in a derived class that is defined in the abstract class. Here is a code sample:

public abstract class AbstractConverter<T, U>
    where U : AbstractConvertible
    where T : AbstractConverter<T, U>
{
    public abstract T Convert(U convertible);
}

public class DerivedConvertibleConverter : AbstractConverter<DerivedConvertibleConverter, DerivedConvertible>
{
    public DerivedConvertibleConverter(DerivedConvertible convertible)
    {
        Convert(convertible);
    }

    public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
    {
        //This will not be called
        System.Console.WriteLine("Called the most derived method");
        return this;
    }

    public DerivedConvertibleConverter Convert(Convertible convertible)
    {
        System.Console.WriteLine("Called the least derived method");
        return this;
    }
}

public abstract class AbstractConvertible {}

public class Convertible : AbstractConvertible {}

public class DerivedConvertible : Convertible {}

In the sample above, the overload of Convert that does not exist in the abstract parent (and is less derived) is called. I would expect that the most derived version, from the parent class, would be called.

In trying to troubleshoot this problem, I ran into an interesting solution:

public abstract class AbstractConverter<U>
    where U : AbstractConvertible
{
    public abstract AbstractConverter<U> Convert(U convertible);
}

public class DerivedConvertibleConverter : AbstractConverter<DerivedConvertible>
{
    public DerivedConvertibleConverter(DerivedConvertible convertible)
    {
        Convert(convertible);
    }

    public override DerivedConvertibleConverter Convert(DerivedConvertible convertible)
    {
        System.Console.WriteLine("Called the most derived method");
        return this;
    }

    public DerivedConvertibleConverter Convert(Convertible convertible)
    {
        System.Console.WriteLine("Called the least derived method");
        return this;
    }
}

public abstract class AbstractConvertible {}

public class Convertible : AbstractConvertible {}

public class DerivedConvertible : Convertible {}

When the derived type argument is removed from the base class, the most derived version of Convert is called. I would not expect this difference, since I would not have expected the interface of the abstract version of Convert to have changed. However, I must be wrong. Can anyone explain why this difference occurs? Thank you very much in advance.

解决方案

In the sample above, the overload of Convert that does not exist in the abstract parent (and is less derived) is called. I would expect that the most derived version, from the parent class, would be called

Many people have this expectation. However, the behaviour you are observing is correct and by design.

The overload resolution algorithm goes like this. First we make a list of all the possible accessible methods you could be calling. Methods which override virtual methods are considered to be methods of the class which declared them, not the class which overrode them. Then we filter out the ones where the arguments cannot be converted to the formal parameter types. Then we filter out all the methods that are on any type less derived than any type that had an applicable method. Then we determine which method is better than another, if there is still more than one method left.

In your case there are two possible applicable methods. The one that takes a DerivedConvertible is considered to be a method of the base class, and is therefore not as good as the one that takes a Convertible.

The principle here is that overriding a virtual method is an implementation detail subject to change, and not a hint to the compiler that the overriding method is to be chosen.

More generally, these features of the overload resolution algorithm are designed to help mitigate various versions of the Brittle Base Class problem.

For more details about these design decisions see my article on the subject:

http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

When the derived type argument is removed from the base class, the most derived version of Convert is called. I would not expect this difference, since I would not have expected the interface of the abstract version of Convert to have changed

The question is based on a false premise; the most derived version is not called. The program fragment is erroneous, and therefore does not compile, and therefore neither method is called; the program doesn't run because it does not compile.

这篇关于使用派生自通用抽象类的类的C#方法重载问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆