C# 在扩展类型中访问扩展方法?

C# 在扩展类型中访问扩展方法?,c#,extension-methods,C#,Extension Methods,我最近一直在重构一些旧代码,很多方法都是对基本类型的扩展方法,比如double,float,int,string,等等。然而,当我慢慢取得巨大进步时,我想到了一个问题。有多种方法可以访问扩展方法。让我们创建一个名为Extensions的容器类,并添加一个基本扩展方法(首先),以及一个使用扩展方法DoIt的简单方法调用dummy的伪类 public static class Extensions { public static double ToRadians(this double de

我最近一直在重构一些旧代码,很多方法都是对基本类型的扩展方法,比如
double
float
int
string
,等等。然而,当我慢慢取得巨大进步时,我想到了一个问题。有多种方法可以访问扩展方法。让我们创建一个名为
Extensions
的容器类,并添加一个基本扩展方法(首先),以及一个使用扩展方法
DoIt
的简单方法调用
dummy
的伪类

public static class Extensions {
    public static double ToRadians(this double degrees) => degrees * Math.PI / 180.0;
}
public class Dummy {
    public void DoIt() {
        double radians = Extensions.ToRadians(45.0);
        double degrees = 90.0;
        radians = degrees.ToRadians();
    }
}
public void DoIt() {
    ...
    WasteOfTime();
    ...
}
这不是最优雅的例子,但它展示了广为人知的对扩展方法的访问。现在,让我们为
Dummy
类创建一个名为
WasteOfTime
的愚蠢而无意义的扩展,但是在
扩展
类中

我不知道你为什么要这样做,但为了这个问题,让我们来做吧

public static class Extensions {
    ...
    public static void WasteOfTime(this Dummy dummy) { }
    ...
}
好的,现在我们有了这个完美的小方法,它应该被放在
Dummy
类中。好的,由于扩展方法使用类型的实例,您应该能够从名为
DoIt
Dummy
class'特殊方法调用
WasteOfTime

public static class Extensions {
    public static double ToRadians(this double degrees) => degrees * Math.PI / 180.0;
}
public class Dummy {
    public void DoIt() {
        double radians = Extensions.ToRadians(45.0);
        double degrees = 90.0;
        radians = degrees.ToRadians();
    }
}
public void DoIt() {
    ...
    WasteOfTime();
    ...
}
哦,等等,你不能这么做!找不到该方法!让我们用
这个
关键字来限定它

this.WasteOfTime();
这样更好,它可以编译!它起作用了!这是浪费时间!酷


重要提示 我想实际上不是这样做的,但出于好奇,我试了一下。如果你能给出一个有效的例子来说明为什么这会是一个好主意,请随意分享,但我相信这是其中之一您当时在想什么实现类型


问题 既然现代编译器不再需要使用
this
关键字限定字段、属性和方法,为什么我必须限定扩展方法


我能想到的唯一一件事是,扩展方法在技术上对基类是静态的。

首先,我要注意,有充分的理由在
上调用扩展方法。例如,您可能正在编写一个集合类,并希望在其中使用LINQ。这没什么错。现在,关于这个问题:

既然现代编译器不再需要用这个关键字限定字段、属性和方法,为什么我必须限定扩展方法

这不是编译器的现代性问题,而是语言规范的内容。根据第12.7.6.3节:

其中一种形式的方法调用(§12.6.6.2)

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )
expr。标识符()
expr。标识符(args)
expr。标识符()
expr。标识符(args)
如果调用的正常处理没有找到适用的方法,则会尝试将构造作为扩展方法调用进行处理。如果expr或任何参数具有编译时类型
dynamic
,则扩展方法将不适用

表单
method()
的方法调用不在这些表单中,因为没有
expr


所以编译器只是遵守规范的规则。至于为什么它是这样设计的,那有点不同。我不知道这方面的细节(尽管我可以看到它们是否在规范的一个注释版本中),但我怀疑
Foo()
可以引用当前类或任何基类中的实例方法或静态方法这一事实会使整个过程变得有点棘手。(从C#6开始,它也可能是一个静态方法,在使用static指令导入的
方法中,请注意……

我想这是一个没有实现的特性,因为它有实现的成本,但没有实现的价值(正如您指出的)没有充分的理由从类内部调用扩展方法来扩展它,但它不是“对基类来说是静态的”。就CLR而言,它不是基类中的任何东西。它是静态类的静态成员。回答来了。。。