2009-09-16T02:49:20の更新内容

programming/tips/extension_method_without_system_core_dll/index.wiki.txt

current previous
1,89 0,0
+
${smdncms:keywords,C# 3.0,拡張メソッド,System.Core.dll,ExtensionAttribute}
+
${smdncms:tags,lang/c#,api/.net}
+
*System.Core.dllを参照せずに拡張メソッドを使用する
+
#googleadunit
+

          
+
C# 3.0から導入された拡張メソッドを使用するにはSystem.Core.dllを参照に追加する必要がある。 これは拡張メソッドを含むコードをコンパイルする際に、System.Core.dllのSystem.Runtime.CompilerServices.ExtensionAttributeを参照するため。
+
しかし、ExtensionAttributeはSystem.Core.dllで宣言されている必要は無く、コンパイル時に同名の属性が参照できればよいので、ExtensionAttributeを自前で宣言すればSystem.Core.dllを参照することなく拡張メソッドを含むコードをコンパイルできるようになる。
+

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

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

          
+
#code(cs,ext-method.cs){{
+
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 {
+
    public static void Main()
+
    {
+
      "Hello, world!\n".WriteTo(Console.Out);
+
    }
+
  }
+
}
+
}}
+

          
+
コンパイル・実行すると次のようにする。 /noconfigを付けないとコンパイラが自動的にSystem.Core.dllへの参照を含めてしまうので注意。
+
#prompt(cscの場合){{
+
C:\>csc /noconfig ext-method.cs
+
Microsoft Visual C# 2008 Compiler version 3.5.30729.1
+
for Microsoft .NET Framework version 3.5
+
Copyright Microsoft Corporation. All rights reserved.
+

          
+
C:\>ext-method.exe
+
Hello, world!
+
}}
+

          
+
#prompt(gmcsの場合){{
+
$ gmcs /noconfig ext-method.cs
+
$ mono ext-method.exe
+
Hello, world!
+
}}
+

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

          
+
ちなみに、System.Core.dllを参照に含めてコンパイルすると、System.Core.dllのExtensionAttributeと自前のものが衝突することになるが、警告となるだけでエラーにはならない。
+

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

          
+
warning CS1685: 定義済みの型 'System.Runtime.CompilerServices.ExtensionAttribute' は、グローバル
+
        エイリアスの複数のアセンブリ内で定義されています。'd:\test\ext-method.cs' からの定義を使用してください。
+
}}
+

          
+
#prompt(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
+
Compilation succeeded - 1 warning(s)
+
}}
+

          
+
-参考
+
--[[Extension methods and .NET 2.0 - Jon Skeet: Coding Blog:http://msmvps.com/blogs/jon_skeet/archive/2007/08/19/extension-methods-and-net-2-0.aspx]]
+
--[[カスタム デザイン バージョンの 'System.Runtime.CompilerServices.ExtensionAttribute' がコンパイラにより検出されましたが、有効ではありません:http://msdn.microsoft.com/ja-jp/library/bb385179.aspx]]
+