C# 3.0から導入された拡張メソッドを使用するにはSystem.Core.dllを参照に追加する必要がある。 これは拡張メソッドを含むコードをコンパイルする際に、System.Core.dllのSystem.Runtime.CompilerServices.ExtensionAttributeを参照するため。

しかし、ExtensionAttributeはSystem.Core.dllで宣言されている必要は無く、コンパイル時に同名の属性が参照できればよいので、ExtensionAttributeを自前で宣言すればSystem.Core.dllを参照することなく拡張メソッドを含むコードをコンパイルできるようになる。

§1 ExtensionAttributeの宣言

ExtensionAttributeを自前で宣言する場合、

  1. 名前空間はSystem.Runtime.CompilerServicesでなければならない(VBの場合、暗黙的な名前空間は使用しない)
  2. AttributeUsageは少なくともAttributeTargets.Assembly, AttributeTargets.Class, AttributeTargets.Methodの三つを含む必要がある(このうち一つでも省略した場合エラーとなる)

の二点に注意する必要がある。

ext-method.cs (System.Core.dllを参照せずに拡張メソッドを使用するコード)
using System;
using System.IO;

namespace System.Runtime.CompilerServices {
  // 拡張メソッドをコンパイルするのに必要となるExtensionAttributeの宣言
  [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
  public sealed class ExtensionAttribute : Attribute {}
}

namespace MyExtensions {
  // 拡張メソッドを含むクラス
  public static class StringExtensions {
    public static void WriteTo(this string str, TextWriter writer)
    {
      writer.Write(str);
    }
  }
}

namespace Test {
  // 拡張メソッドを使用するコード
  using MyExtensions;

  class MainClass {
    static void Main()
    {
      "Hello, world!\n".WriteTo(Console.Out);
    }
  }
}

コンパイル・実行すると次のようになる。 コンパイルオプション /noconfig を付けないとコンパイラが自動的にSystem.Core.dllへの参照を含めてしまうので注意。

cscの場合
C:\>csc /noconfig ext-method.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

C:\>ext-method.exe
Hello, world!
gmcsの場合
$ gmcs /noconfig ext-method.cs
$ mono ext-method.exe
Hello, world!

このようにすることでSystem.Core.dllを参照する必要がなくなるため、拡張メソッドを含むコードでも.NET Framework 2.0をターゲットとしてコンパイルできるようになる。

§2 System.Core.dllのExtensionAttributeとの衝突

このようにして宣言したExtensionAttributeが存在する状態でSystem.Core.dllを参照に含めてコンパイルすると、System.Core.dllのExtensionAttributeと自前のものが衝突することになる。 例えばコンパイルオプション /noconfig を付けずにコンパイルすると衝突が起こるが、仮にExtensionAttributeが衝突しても警告(CS1685)となるだけでエラーにはならない。

cscの場合
C:\>csc /r:System.Core.dll ext-method.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

warning CS1685: 定義済みの型 'System.Runtime.CompilerServices.ExtensionAttribute' は、グローバル
        エイリアスの複数のアセンブリ内で定義されています。'd:\test\ext-method.cs' からの定義を使用してください。
gmcsの場合
$ gmcs /r:System.Core.dll ext-method.cs
ext-method.cs(6,23): warning CS1685: The predefined type `System.Runtime.CompilerServices.ExtensionAttribute' is ambiguous. Using definition from `System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
/usr/local/lib/mono/gac/System.Core/3.5.0.0__b77a5c561934e089/System.Core.dll (Location of the symbol related to previous warning)
Compilation succeeded - 1 warning(s)

System.Core.dllを参照する場合でもコンパイルオプションに /nowarn:1685 を指定すればこの警告は表示されなくなる。

cscの場合
C:\>csc /r:System.Core.dll /nowarn:1685 ext-method.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
gmcsの場合
$ gmcs /r:System.Core.dll /nowarn:1685 ext-method.cs

ソース中に #pragma warning disable 1685 と記述してもこの警告は抑止できない。