C# 我可以向现有的静态类添加扩展方法吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/249222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I add extension methods to an existing static class?
提问by Leon Bambrick
I'm a fan of extension methods in C#, but haven't had any success adding an extension method to a static class, such as Console.
我很喜欢 C# 中的扩展方法,但是在将扩展方法添加到静态类(例如 Console)中没有任何成功。
For example, if I want to add an extension to Console, called 'WriteBlueLine', so that I can go:
例如,如果我想向控制台添加一个名为“WriteBlueLine”的扩展,以便我可以:
Console.WriteBlueLine("This text is blue");
I tried this by adding a local, public static method, with Console as a 'this' parameter... but no dice!
我通过添加一个本地的公共静态方法来尝试这个,控制台作为一个'this'参数......但没有骰子!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
This didn't add a 'WriteBlueLine' method to Console... am I doing it wrong? Or asking for the impossible?
这并没有向控制台添加“WriteBlueLine”方法......我做错了吗?还是要求不可能的?
采纳答案by tvanfosson
No. Extension methods require an instance variable (value) for an object. You can however, write a static wrapper around the ConfigurationManager
interface. If you implement the wrapper, you don't need an extension method since you can just add the method directly.
否。扩展方法需要对象的实例变量(值)。但是,您可以围绕ConfigurationManager
接口编写静态包装器。如果您实现包装器,则不需要扩展方法,因为您可以直接添加该方法。
public static class ConfigurationManagerWrapper
{
public static ConfigurationSection GetSection( string name )
{
return ConfigurationManager.GetSection( name );
}
.....
public static ConfigurationSection GetWidgetSection()
{
return GetSection( "widgets" );
}
}
回答by Brannon
You can't add staticmethods to a type. You can only add (pseudo-)instance methods to an instance of a type.
您不能向类型添加静态方法。您只能向类型的实例添加(伪)实例方法。
The point of the this
modifier is to tell the C# compiler to pass the instance on the left-side of the .
as the first parameter of the static/extension method.
所述的点this
改性剂是告诉C#编译器上的左侧通过实例.
为静态/扩展方法的第一个参数。
In the case of adding static methods to a type, there is no instance to pass for the first parameter.
在向类型添加静态方法的情况下,第一个参数没有要传递的实例。
回答by Robert S.
I tried to do this with System.Environment back when I was learning extension methods and was not successful. The reason is, as others mention, because extension methods require an instance of the class.
当我学习扩展方法时,我尝试使用 System.Environment 来做到这一点,但没有成功。正如其他人提到的,原因是因为扩展方法需要类的实例。
回答by Robert S.
Nope. Extension method definitions require an instance of the type you're extending. Its unfortunate; I'm not sure why its required...
不。扩展方法定义需要您正在扩展的类型的实例。不幸的是; 我不确定为什么需要它...
回答by Tom Deloford
Its not possible.
这是不可能的。
And yes I think MS made a mistake here.
是的,我认为 MS 在这里犯了一个错误。
Their decision does not make sense and forces programmers to write (as described above) a pointless wrapper class.
他们的决定没有意义,并迫使程序员编写(如上所述)一个毫无意义的包装类。
Here is a good example: Trying to extend static MS Unit testing class Assert: I want 1 more Assert method AreEqual(x1,x2)
.
这是一个很好的例子:尝试扩展静态 MS 单元测试类 Assert:我想要 1 个更多的 Assert 方法AreEqual(x1,x2)
。
The only way to do this is to point to different classes or write a wrapper around 100s of different Assert methods. Why!?
做到这一点的唯一方法是指向不同的类或围绕 100 多种不同的 Assert 方法编写包装器。为什么!?
If the decision was been made to allow extensions of instances I see no logical reason to not allow static extensions. The arguments about sectioning libraries does not stand up once instances can be extended.
如果决定允许扩展实例,我认为没有逻辑理由不允许静态扩展。一旦可以扩展实例,关于对库进行分区的争论就站不住脚了。
回答by Pag Sun
Maybe you could add a static class with your custom namespace and the same class name:
也许您可以使用自定义命名空间和相同的类名添加一个静态类:
using CLRConsole = System.Console;
namespace ExtensionMethodsDemo
{
public static class Console
{
public static void WriteLine(string value)
{
CLRConsole.WriteLine(value);
}
public static void WriteBlueLine(string value)
{
System.ConsoleColor currentColor = CLRConsole.ForegroundColor;
CLRConsole.ForegroundColor = System.ConsoleColor.Blue;
CLRConsole.WriteLine(value);
CLRConsole.ForegroundColor = currentColor;
}
public static System.ConsoleKeyInfo ReadKey(bool intercept)
{
return CLRConsole.ReadKey(intercept);
}
}
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteBlueLine("This text is blue");
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
}
}
回答by Tenaka
You CAN do this if you are willing to "frig" it a little by making a variable of the static class and assigning it to null. However, this method would not be available to static calls on the class, so not sure how much use it would be:
如果您愿意通过创建静态类的变量并将其分配为 null 来稍微“控制”它,则可以执行此操作。但是,此方法不可用于类上的静态调用,因此不确定它的用途有多大:
Console myConsole = null;
myConsole.WriteBlueLine("my blue line");
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
回答by Mr. Obnoxious
Can you add static extensions to classes in C#? No but you can do this:
你能在 C# 中为类添加静态扩展吗?不,但你可以这样做:
public static class Extensions
{
public static T Create<T>(this T @this)
where T : class, new()
{
return Utility<T>.Create();
}
}
public static class Utility<T>
where T : class, new()
{
static Utility()
{
Create = Expression.Lambda<Func<T>>(Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))).Compile();
}
public static Func<T> Create { get; private set; }
}
Here's how it works. While you can't technically write static extension methods, instead this code exploits a loophole in extension methods. That loophole being that you can call extension methods on null objects without getting the null exception (unless you access anything via @this).
这是它的工作原理。虽然您在技术上无法编写静态扩展方法,但这段代码利用了扩展方法中的漏洞。这个漏洞是你可以在空对象上调用扩展方法而不会得到空异常(除非你通过@this 访问任何东西)。
So here's how you would use this:
所以这里是你将如何使用它:
var ds1 = (null as DataSet).Create(); // as oppose to DataSet.Create()
// or
DataSet ds2 = null;
ds2 = ds2.Create();
// using some of the techniques above you could have this:
(null as Console).WriteBlueLine(...); // as oppose to Console.WriteBlueLine(...)
Now WHY did I pick calling the default constructor as an example, and AND why don't I just return new T() in the first code snippet without doing all of that Expression garbage? Well todays your lucky day because you get a 2fer. As any advanced .NET developer knows, new T() is slow because it generates a call to System.Activator which uses reflection to get the default constructor before calling it. Damn you Microsoft! However my code calls the default constructor of the object directly.
现在为什么我选择调用默认构造函数作为示例,为什么我不在第一个代码片段中返回 new T() 而不执行所有表达式垃圾?那么今天是你的幸运日,因为你得到了 2fer。任何高级 .NET 开发人员都知道,new T() 很慢,因为它会生成对 System.Activator 的调用,后者在调用之前使用反射获取默认构造函数。该死的微软!但是我的代码直接调用对象的默认构造函数。
Static extensions would be better than this but desperate times call for desperate measures.
静态扩展会比这更好,但绝望的时代需要绝望的措施。
回答by Brian Griffin
As for extension methods, extension methods themselves are static; but they are invoked as if they are instance methods. Since a static class is not instantiable, you would never have an instance of the class to invoke an extension method from. For this reason the compiler does not allow extension methods to be defined for static classes.
至于扩展方法,扩展方法本身是静态的;但是它们被调用时就好像它们是实例方法一样。由于静态类不可实例化,因此您永远不会有该类的实例来调用扩展方法。为此,编译器不允许为静态类定义扩展方法。
Mr. Obnoxious wrote: "As any advanced .NET developer knows, new T() is slow because it generates a call to System.Activator which uses reflection to get the default constructor before calling it".
Obnoxious 先生写道:“任何高级 .NET 开发人员都知道,new T() 很慢,因为它生成对 System.Activator 的调用,后者在调用之前使用反射获取默认构造函数”。
New() is compiled to the IL "newobj" instruction if the type is known at compile time. Newobj takes a constructor for direct invocation. Calls to System.Activator.CreateInstance() compile to the IL "call" instruction to invoke System.Activator.CreateInstance(). New() when used against generic types will result in a call to System.Activator.CreateInstance(). The post by Mr. Obnoxious was unclear on this point... and well, obnoxious.
如果类型在编译时已知,则 New() 被编译为 IL“newobj”指令。Newobj 使用构造函数进行直接调用。对 System.Activator.CreateInstance() 的调用编译为 IL“调用”指令以调用 System.Activator.CreateInstance()。New() 用于泛型类型时将导致调用 System.Activator.CreateInstance()。Obnoxious 先生的帖子在这一点上不清楚......而且,令人讨厌。
This code:
这段代码:
System.Collections.ArrayList _al = new System.Collections.ArrayList();
System.Collections.ArrayList _al2 = (System.Collections.ArrayList)System.Activator.CreateInstance(typeof(System.Collections.ArrayList));
produces this IL:
产生这个 IL:
.locals init ([0] class [mscorlib]System.Collections.ArrayList _al,
[1] class [mscorlib]System.Collections.ArrayList _al2)
IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_0006: stloc.0
IL_0007: ldtoken [mscorlib]System.Collections.ArrayList
IL_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0011: call object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type)
IL_0016: castclass [mscorlib]System.Collections.ArrayList
IL_001b: stloc.1
回答by Black Dog
yes, in a limited sense.
是的,在有限的意义上。
public class DataSet : System.Data.DataSet
{
public static void SpecialMethod() { }
}
This works but Console doesn't because it's static.
这有效,但 Console 无效,因为它是静态的。
public static class Console
{
public static void WriteLine(String x)
{ System.Console.WriteLine(x); }
public static void WriteBlueLine(String x)
{
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.Write(.x);
}
}
This works because as long as it's not on the same namespace. The problem is that you have to write a proxy static method for every method that System.Console have. It's not necessarily a bad thing as you can add something like this:
这是有效的,因为只要它不在同一个命名空间中。问题是您必须为 System.Console 拥有的每个方法编写一个代理静态方法。这不一定是坏事,因为您可以添加如下内容:
public static void WriteLine(String x)
{ System.Console.WriteLine(x.Replace("Fck","****")); }
or
或者
public static void WriteLine(String x)
{
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.WriteLine(x);
}
The way it works is that you hook something into the standard WriteLine. It could be a line count or bad word filter or whatever. Whenever you just specify Console in your namespace say WebProject1 and import the namespace System, WebProject1.Console will be chosen over System.Console as default for those classes in namespace WebProject1. So this code will turn all the Console.WriteLine calls into blue insofar as you never specified System.Console.WriteLine.
它的工作方式是将某些东西挂接到标准的 WriteLine 中。它可能是行数或坏词过滤器或其他什么。每当您在命名空间中指定 Console 时说 WebProject1 并导入命名空间 System,WebProject1.Console 将被选择而不是 System.Console 作为命名空间 WebProject1 中的那些类的默认值。因此,只要您从未指定 System.Console.WriteLine,此代码会将所有 Console.WriteLine 调用变为蓝色。