为什么不支持C#静态类扩展方法?

时间:2022-09-02 11:57:37

I know from this question that extension methods can only operate on class instances, not the static class itself. This means I can't extend useful static classes like Convert and Math.

我从这个问题中知道扩展方法只能在类实例上运行,而不能在静态类本身上运行。这意味着我无法扩展有用的静态类,如Convert和Math。

What I want to know is, why is this the case? From the link above, there are some suggestions on how the C# team could have implemented this kind of functionality. Is there some philosophical reason why it isn't supported?

我想知道的是,为什么会这样呢?从上面的链接,有一些关于C#团队如何实现这种功能的建议。是否有一些哲学上的原因导致它不被支持?

For example, here's a rationale behind why there is no built-in LINQ ForEach<T> extension for IEnumerable<T>.

例如,这里有一个理由,为什么IEnumerable 没有内置的LINQ ForEach 扩展。

6 个解决方案

#1


68  

the C# team could have implemented this kind of functionality. Is there some philosophical reason why it isn't supported?

C#团队可以实现这种功能。是否有一些哲学上的原因导致它不被支持?

There's no technical reason, and no philosophical reason. However, as I often point out, I don't have to provide a justification for not doing a feature. Features aren't cheap; they are extremely expensive and they must not only justify their own cost, they must justify the opportunity cost of not doing the hundred other features we could have done with that budget. We must justify the cost of features to our stakeholders, but we need not justify saving time and effort by not implementing features that don't meet our bar.

没有技术原因,也没有哲学原因。但是,正如我经常指出的那样,我没有必要提供不做功能的理由。功能不便宜;它们非常昂贵,而且它们不仅要证明自己的成本是合理的,而且还必须证明没有完成我们本可以用这个预算完成的其他一百个功能的机会成本。我们必须证明我们的利益相关者的功能成本合理,但我们不需要通过不实现不符合我们标准的功能来节省时间和精力。

In particular, the proposed feature does nothing for LINQ; extension methods were added to make LINQ work. Anything that didn't make LINQ work was very hard to get into C# 3.0; we had a lot of work on the schedule and not much time to do it in. (I was surprised that automatic properties made it in.) Cutting an unnecessary feature before even designing it saved a lot of time and effort that was spent on other things that do make LINQ work.

特别是,建议的功能对LINQ没有任何作用;添加了扩展方法以使LINQ工作。任何没有使LINQ工作的东西都很难进入C#3.0;我们在日程安排上做了很多工作而没有太多时间去做。(我很惊讶自动属性使它成功。)在设计它之前削减不必要的功能节省了大量的时间和精力花在了其他使LINQ工作的事情。

In short: the suggested feature has never met our bar for net benefit over cost, and we've always had more important features to spend our limited time and effort on.

简而言之:建议的功能从未达到我们的净成本超过成本的标准,我们总是有更重要的功能来花费我们有限的时间和精力。

#2


10  

After reading through the answers, as well as some related questions, I've assembled my understanding of the issue here.

在阅读了答案以及一些相关问题之后,我在这里总结了我对这个问题的理解。

How extension methods work

First, it's important to realize that extensions are just syntactic sugar for static methods.

首先,重要的是要认识到扩展只是静态方法的语法糖。

// Say you have an extension method that looks like this:
class Extensions
{
    public static void Extend(this SomeClass foo) {}
}

// Here's how you call it
SomeClass myClass;
myClass.Extend();

// The compiler converts it to this:
Extensions.Extend(myClass);

The method doesn't actually become part of the class. This is why you can't access private members from an extension method. Extension methods change C# syntax only, and do not violate the concept of OOP accessibility. In fact, if you write an extension method and a normal static method that do the same thing, then decompile the MSIL, they are exactly the same.

该方法实际上并不成为该类的一部分。这就是您无法从扩展方法访问私有成员的原因。扩展方法仅改变C#语法,并且不违反OOP可访问性的概念。实际上,如果你编写一个扩展方法和一个执行相同操作的普通静态方法,那么反编译MSIL,它们完全相同。

Why extension methods exist

So if they don't add actual functionality, why have extension methods at all? The answer is LINQ:

因此,如果他们不添加实际功能,为什么要使用扩展方法呢?答案是LINQ:

// LINQ makes this easy to read
array.Where(i => i&1 == 0).Select(i => i*i);

// Without extension methods, we would have to do it like this
Enumerable.Select(Enumerable.Where(array, i => i&1 == 0), i => i*i);

In a way, all of LINQ is just syntactic sugar, since everything it can do could be written in a clunky, non LINQy way. Obviously the C# team felt that the readability gained by LINQ was worth it, but it begs the question, "why did they stop there?"

在某种程度上,所有LINQ都只是语法糖,因为它可以做的一切都可以用一种笨重的非LINQy方式编写。显然,C#团队认为LINQ获得的可读性是值得的,但它引出了一个问题,“为什么他们会停在那里?”

Why not other extension types?

Eric Lippert, one of the C# compiler devs, described in a blog post that a huge part of C# 3 was creating all of the constructs necessary for LINQ: "implicitly typed locals, anonymous types, lambda expressions, extension methods, object and collection initializers, query comprehensions, expression trees, [and] improved method type inference." Because the C# team was the most resource-limited team for the 2008 .NET release, additional types of extensions that weren't strictly necessary for LINQ were not included.

C#编译器开发人员Eric Lippert在博客文章中描述了C#3的很大一部分是创建LINQ所需的所有构造:“隐式类型化本地化,匿名类型,lambda表达式,扩展方法,对象和集合初始化器,查询理解,表达式树,[和]改进的方法类型推断。“由于C#团队是2008 .NET版本中资源最有限的团队,因此不包括LINQ不是必需的其他类型的扩展。

The team did consider implementing extension properties in C# 4, and actually wrote a working prototype, but it was dropped when they discovered it would not enable the WPF team as implemented (which was one of the motivators for the feature). Eric Lipper later said they they did consider extension methods for static classes, but could not justify the real-world benefits against the costs of implementation, testing, and maintenance.

团队确实考虑在C#4中实现扩展属性,并且实际上编写了一个工作原型,但是当它们发现它不能使WPF团队实现时(这是该功能的激励因素之一),它被删除了。 Eric Lipper后来表示,他们确实考虑过静态类的扩展方法,但无法证明实现,测试和维护成本的实际效益。

A workaround

It is possible to write an extension method that gets close:

可以编写一个接近的扩展方法:

public static TResult DoSomething<TType, TResult>(this TType @class)
    {
        // access static methods with System.Reflection
        return default(TResult);
    }

// This works, but poorly
typeof(Math).DoSomething();
typeof(Convert).DoSomething();

But it's pretty ugly. It requires reflection, and can't support any kind of intelligent typing, since any Type can call it and that's likely not the intended functionality.

但它非常丑陋。它需要反射,并且不能支持任何类型的智能打字,因为任何类型都可以调用它,这可能不是预期的功能。

#3


3  

I believe the answer for your question is because it doesn't make any sense to extend with static methods. Main reason behind introducing Extension methods is not extending class which you do not own. Main reason is that it will allow reduce methods nesting in examples like these:

我相信你的问题的答案是因为用静态方法扩展没有任何意义。引入Extension方法背后的主要原因不是扩展您不拥有的类。主要原因是它允许在这些示例中嵌套reduce方法:

 Enumerable.Select(Enumerable.Where(arr, i => i & 1 == 0), i => i*i); // not the best thing I ever read

 arr.Where(i => i&1 == 0).Select(i => i*i); // wow, I see! These are squares for odd numbers

That is why there is no such point to have extension methods for static classes.

这就是为什么没有这样的观点来为静态类提供扩展方法。

#4


3  

Extension methods operate on objects, not classes. If you want an extension method to operate on a class, I suppose you could do this:

扩展方法对对象而不是类进行操作。如果你想要一个扩展方法来操作类,我想你可以这样做:

public static T DoSomething<T>(this T @class) 
    where T:Type
{
    // access static methods via reflection...
    return @class;
}

#5


2  

Static extensions are possible in F# :

F#中可以进行静态扩展:

type Platform = 
    | Win32
    | X64
    override this.ToString() = 
        match FSharpValue.GetUnionFields(this, typeof<Platform>) with
        | case, _ -> case.Name.Replace('X', 'x')

type Environment with
    static member Platform =
        if System.IntPtr.Size = 8 then Platform.X64 else Platform.Win32

#6


1  

Well its not only about not implemented, but it will cause confusion of where the method belongs to? Static extensions were introduced because linq came in later version and only to support linq in easy to code way, static extensions are useful.

那么它不仅没有实现,而且会引起方法所属的混淆?引入静态扩展是因为linq出现在更高版本中,并且只是为了以易于编码的方式支持linq,静态扩展很有用。

Static extensions are useful only to make code more readable. It has no significance at runtime or compile time.

静态扩展仅用于使代码更具可读性。它在运行时或编译时没有意义。

#1


68  

the C# team could have implemented this kind of functionality. Is there some philosophical reason why it isn't supported?

C#团队可以实现这种功能。是否有一些哲学上的原因导致它不被支持?

There's no technical reason, and no philosophical reason. However, as I often point out, I don't have to provide a justification for not doing a feature. Features aren't cheap; they are extremely expensive and they must not only justify their own cost, they must justify the opportunity cost of not doing the hundred other features we could have done with that budget. We must justify the cost of features to our stakeholders, but we need not justify saving time and effort by not implementing features that don't meet our bar.

没有技术原因,也没有哲学原因。但是,正如我经常指出的那样,我没有必要提供不做功能的理由。功能不便宜;它们非常昂贵,而且它们不仅要证明自己的成本是合理的,而且还必须证明没有完成我们本可以用这个预算完成的其他一百个功能的机会成本。我们必须证明我们的利益相关者的功能成本合理,但我们不需要通过不实现不符合我们标准的功能来节省时间和精力。

In particular, the proposed feature does nothing for LINQ; extension methods were added to make LINQ work. Anything that didn't make LINQ work was very hard to get into C# 3.0; we had a lot of work on the schedule and not much time to do it in. (I was surprised that automatic properties made it in.) Cutting an unnecessary feature before even designing it saved a lot of time and effort that was spent on other things that do make LINQ work.

特别是,建议的功能对LINQ没有任何作用;添加了扩展方法以使LINQ工作。任何没有使LINQ工作的东西都很难进入C#3.0;我们在日程安排上做了很多工作而没有太多时间去做。(我很惊讶自动属性使它成功。)在设计它之前削减不必要的功能节省了大量的时间和精力花在了其他使LINQ工作的事情。

In short: the suggested feature has never met our bar for net benefit over cost, and we've always had more important features to spend our limited time and effort on.

简而言之:建议的功能从未达到我们的净成本超过成本的标准,我们总是有更重要的功能来花费我们有限的时间和精力。

#2


10  

After reading through the answers, as well as some related questions, I've assembled my understanding of the issue here.

在阅读了答案以及一些相关问题之后,我在这里总结了我对这个问题的理解。

How extension methods work

First, it's important to realize that extensions are just syntactic sugar for static methods.

首先,重要的是要认识到扩展只是静态方法的语法糖。

// Say you have an extension method that looks like this:
class Extensions
{
    public static void Extend(this SomeClass foo) {}
}

// Here's how you call it
SomeClass myClass;
myClass.Extend();

// The compiler converts it to this:
Extensions.Extend(myClass);

The method doesn't actually become part of the class. This is why you can't access private members from an extension method. Extension methods change C# syntax only, and do not violate the concept of OOP accessibility. In fact, if you write an extension method and a normal static method that do the same thing, then decompile the MSIL, they are exactly the same.

该方法实际上并不成为该类的一部分。这就是您无法从扩展方法访问私有成员的原因。扩展方法仅改变C#语法,并且不违反OOP可访问性的概念。实际上,如果你编写一个扩展方法和一个执行相同操作的普通静态方法,那么反编译MSIL,它们完全相同。

Why extension methods exist

So if they don't add actual functionality, why have extension methods at all? The answer is LINQ:

因此,如果他们不添加实际功能,为什么要使用扩展方法呢?答案是LINQ:

// LINQ makes this easy to read
array.Where(i => i&1 == 0).Select(i => i*i);

// Without extension methods, we would have to do it like this
Enumerable.Select(Enumerable.Where(array, i => i&1 == 0), i => i*i);

In a way, all of LINQ is just syntactic sugar, since everything it can do could be written in a clunky, non LINQy way. Obviously the C# team felt that the readability gained by LINQ was worth it, but it begs the question, "why did they stop there?"

在某种程度上,所有LINQ都只是语法糖,因为它可以做的一切都可以用一种笨重的非LINQy方式编写。显然,C#团队认为LINQ获得的可读性是值得的,但它引出了一个问题,“为什么他们会停在那里?”

Why not other extension types?

Eric Lippert, one of the C# compiler devs, described in a blog post that a huge part of C# 3 was creating all of the constructs necessary for LINQ: "implicitly typed locals, anonymous types, lambda expressions, extension methods, object and collection initializers, query comprehensions, expression trees, [and] improved method type inference." Because the C# team was the most resource-limited team for the 2008 .NET release, additional types of extensions that weren't strictly necessary for LINQ were not included.

C#编译器开发人员Eric Lippert在博客文章中描述了C#3的很大一部分是创建LINQ所需的所有构造:“隐式类型化本地化,匿名类型,lambda表达式,扩展方法,对象和集合初始化器,查询理解,表达式树,[和]改进的方法类型推断。“由于C#团队是2008 .NET版本中资源最有限的团队,因此不包括LINQ不是必需的其他类型的扩展。

The team did consider implementing extension properties in C# 4, and actually wrote a working prototype, but it was dropped when they discovered it would not enable the WPF team as implemented (which was one of the motivators for the feature). Eric Lipper later said they they did consider extension methods for static classes, but could not justify the real-world benefits against the costs of implementation, testing, and maintenance.

团队确实考虑在C#4中实现扩展属性,并且实际上编写了一个工作原型,但是当它们发现它不能使WPF团队实现时(这是该功能的激励因素之一),它被删除了。 Eric Lipper后来表示,他们确实考虑过静态类的扩展方法,但无法证明实现,测试和维护成本的实际效益。

A workaround

It is possible to write an extension method that gets close:

可以编写一个接近的扩展方法:

public static TResult DoSomething<TType, TResult>(this TType @class)
    {
        // access static methods with System.Reflection
        return default(TResult);
    }

// This works, but poorly
typeof(Math).DoSomething();
typeof(Convert).DoSomething();

But it's pretty ugly. It requires reflection, and can't support any kind of intelligent typing, since any Type can call it and that's likely not the intended functionality.

但它非常丑陋。它需要反射,并且不能支持任何类型的智能打字,因为任何类型都可以调用它,这可能不是预期的功能。

#3


3  

I believe the answer for your question is because it doesn't make any sense to extend with static methods. Main reason behind introducing Extension methods is not extending class which you do not own. Main reason is that it will allow reduce methods nesting in examples like these:

我相信你的问题的答案是因为用静态方法扩展没有任何意义。引入Extension方法背后的主要原因不是扩展您不拥有的类。主要原因是它允许在这些示例中嵌套reduce方法:

 Enumerable.Select(Enumerable.Where(arr, i => i & 1 == 0), i => i*i); // not the best thing I ever read

 arr.Where(i => i&1 == 0).Select(i => i*i); // wow, I see! These are squares for odd numbers

That is why there is no such point to have extension methods for static classes.

这就是为什么没有这样的观点来为静态类提供扩展方法。

#4


3  

Extension methods operate on objects, not classes. If you want an extension method to operate on a class, I suppose you could do this:

扩展方法对对象而不是类进行操作。如果你想要一个扩展方法来操作类,我想你可以这样做:

public static T DoSomething<T>(this T @class) 
    where T:Type
{
    // access static methods via reflection...
    return @class;
}

#5


2  

Static extensions are possible in F# :

F#中可以进行静态扩展:

type Platform = 
    | Win32
    | X64
    override this.ToString() = 
        match FSharpValue.GetUnionFields(this, typeof<Platform>) with
        | case, _ -> case.Name.Replace('X', 'x')

type Environment with
    static member Platform =
        if System.IntPtr.Size = 8 then Platform.X64 else Platform.Win32

#6


1  

Well its not only about not implemented, but it will cause confusion of where the method belongs to? Static extensions were introduced because linq came in later version and only to support linq in easy to code way, static extensions are useful.

那么它不仅没有实现,而且会引起方法所属的混淆?引入静态扩展是因为linq出现在更高版本中,并且只是为了以易于编码的方式支持linq,静态扩展很有用。

Static extensions are useful only to make code more readable. It has no significance at runtime or compile time.

静态扩展仅用于使代码更具可读性。它在运行时或编译时没有意义。