C# 3.0から導入された拡張メソッドを使用するにはSystem.Core.dllを参照に追加する必要がある。 これは拡張メソッドを含むコードをコンパイルする際に、System.Core.dllのSystem.Runtime.CompilerServices.ExtensionAttributeを参照するため。
しかし、ExtensionAttributeはSystem.Core.dllで宣言されている必要は無く、コンパイル時に同名の属性が参照できればよいので、ExtensionAttributeを自前で宣言すればSystem.Core.dllを参照することなく拡張メソッドを含むコードをコンパイルできるようになる。
ExtensionAttributeの宣言
ExtensionAttributeを自前で宣言する場合、
- 名前空間はSystem.Runtime.CompilerServicesでなければならない(VBの場合、暗黙的な名前空間は使用しない)
- AttributeUsageは少なくともAttributeTargets.Assembly, AttributeTargets.Class, AttributeTargets.Methodの三つを含む必要がある(このうち一つでも省略した場合エラーとなる)
の二点に注意する必要がある。
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への参照を含めてしまうので注意。
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 /noconfig ext-method.cs $ mono ext-method.exe Hello, world!
このようにすることでSystem.Core.dllを参照する必要がなくなるため、拡張メソッドを含むコードでも.NET Framework 2.0をターゲットとしてコンパイルできるようになる。
System.Core.dllのExtensionAttributeとの衝突
このようにして宣言したExtensionAttributeが存在する状態でSystem.Core.dllを参照に含めてコンパイルすると、System.Core.dllのExtensionAttributeと自前のものが衝突することになる。 例えばコンパイルオプション /noconfig を付けずにコンパイルすると衝突が起こるが、仮にExtensionAttributeが衝突しても警告(CS1685)となるだけでエラーにはならない。
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 /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 を指定すればこの警告は表示されなくなる。
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 /r:System.Core.dll /nowarn:1685 ext-method.cs
ソース中に #pragma warning disable 1685 と記述してもこの警告は抑止できない。