我是c#中扩展方法的粉丝,但还没有成功地将扩展方法添加到静态类中,比如Console。

例如,如果我想添加一个名为“WriteBlueLine”的扩展到控制台,这样我就可以:

Console.WriteBlueLine("This text is blue");

我尝试通过添加一个本地的公共静态方法,并将Console作为“this”参数…但是不行!

public static class Helpers {
    public static void WriteBlueLine(this Console c, string text)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Console.WriteLine(text);
        Console.ResetColor();
    }
}

这没有添加'WriteBlueLine'方法控制台…我做错了吗?或者要求不可能的事情?


当前回答

至于扩展方法,扩展方法本身是静态的;但是它们被调用时就好像它们是实例方法一样。由于静态类是不可实例化的,因此永远不会有该类的实例来从中调用扩展方法。因此,编译器不允许为静态类定义扩展方法。

obannoy先生写道:“任何高级的。net开发人员都知道,new T()很慢,因为它生成了一个对System的调用。激活器,在调用它之前使用反射来获取默认构造函数”。

如果New()类型在编译时已知,则编译为IL "newobj"指令。Newobj接受一个用于直接调用的构造函数。调用System.Activator.CreateInstance()编译为IL“call”指令来调用System.Activator.CreateInstance()。对泛型类型使用New()将导致对System.Activator.CreateInstance()的调用。讨厌先生的帖子在这一点上不清楚……嗯,令人讨厌。

这段代码:

System.Collections.ArrayList _al = new System.Collections.ArrayList();
System.Collections.ArrayList _al2 = (System.Collections.ArrayList)System.Activator.CreateInstance(typeof(System.Collections.ArrayList));

产生此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

其他回答

虽然Console的方法是静态的,但它的静态方法Write()和WriteLine()只是分别将调用重定向到Console. out .Write()和Console. out .WriteLine()。Out是一个实例,其类型派生自抽象类TextWriter。这使得为TextWriter定义扩展方法成为可能:

public static class ConsoleTextWriterExtensions
{
    public static void WriteBlueLine(this TextWriter writer, string text)
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        writer.WriteLine(text);
        Console.ResetColor();
    }

    public static void WriteUppercase(this TextWriter writer, string text)
    {
        writer.Write(text.ToUpper());
    }
}

然后可以像这样调用该方法:

Console.Out.WriteBlueLine();

最好的部分是标准错误流实例Console的类型。错误也源于TextWriter,这使得相同的扩展方法也可用于控制台。错误:

Console.Error.WriteBlueLine();

如果您已经定义了像WriteTable()这样的扩展方法(用于将表写入控制台),那么这可能非常有用,因为您还可以将它用于错误流或TextWriter的任何其他对象。

新版本的c#甚至可以用using static语句来获得控制台的红色。前缀:

using static System.Console;

Out.WriteBlueLine("A blue line");
Error.WriteBlueLine("A blue line");

我试着用系统来做这件事。当时我正在学习扩展方法,但没有成功。正如其他人提到的,原因是扩展方法需要类的实例。

不能向类型添加静态方法。只能向某个类型的实例添加(伪)实例方法。

this修饰符的作用是告诉c#编译器将实例传递到。作为静态/扩展方法的第一个参数。

在向类型添加静态方法的情况下,没有为第一个参数传递实例。

也许你可以用你的自定义命名空间和相同的类名添加一个静态类:

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);
        }
    }
}

以下内容作为对tvanfosson回答的编辑被拒绝。我被要求把它作为我自己的答案。我使用了他的建议并完成了ConfigurationManager包装器的实现。原则上我只是填了…在tvanfosson的回答中。

不。扩展方法需要对象的实例。你可以 但是,在ConfigurationManager周围编写一个静态包装器 接口。如果实现了包装器,就不需要扩展 方法,因为您可以直接添加方法。

public static class ConfigurationManagerWrapper
{
    public static NameValueCollection AppSettings
    {
        get { return ConfigurationManager.AppSettings; }
    }

    public static ConnectionStringSettingsCollection ConnectionStrings
    {
        get { return ConfigurationManager.ConnectionStrings; }
    }

    public static object GetSection(string sectionName)
    {
        return ConfigurationManager.GetSection(sectionName);
    }

    public static Configuration OpenExeConfiguration(string exePath)
    {
        return ConfigurationManager.OpenExeConfiguration(exePath);
    }

    public static Configuration OpenMachineConfiguration()
    {
        return ConfigurationManager.OpenMachineConfiguration();
    }

    public static Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
    {
        return ConfigurationManager.OpenMappedExeConfiguration(fileMap, userLevel);
    }

    public static Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap)
    {
        return ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
    }

    public static void RefreshSection(string sectionName)
    {
        ConfigurationManager.RefreshSection(sectionName);
    }
}