本エントリーには誤った内容が含まれています。代わりにC#の言語バージョンと.NET Frameworkバージョン | ++C++; // 未確認飛行 C ブログ を参照してください。
.NET2.0 の案件、私は今や携わることはほとんど無いのですが、時おり社内での悲鳴を耳にします。
.NET2.0 であっても糖衣構文系の機能であれば新しい Visual Studio やコンパイラを使用することで利用可能です。
- 暗黙的に型指定されたローカル変数(var)
- 自動実装プロパティ
- ラムダ式
- オブジェクト/コレクション初期化子
ところが、拡張メソッドについては私はこれまで .NET3.5 が必要だと思っていました。
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
"a".Fuga();
}
}
public static class Hoge
{
public static void Fuga(this string a)
{
}
}
}
拡張メソッドは、その定義箇所と利用箇所(呼び出し側)がアセンブリを跨ぐ場合もあるため、属性によるマークが必要になります。そのため、属性クラスが含まれない .NET2.0 では使うことができないと。
…そう思っていた時期が私にもありました。
どうやら、同じ名前空間、同じ名前の属性クラスを自分で定義してあげれば使えるということが判明しました。
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute
{
}
}
これを利用すれば自作の Enumerable
クラスを定義することで LINQ が利用可能に。
夢が広がりんぐです。
おまけ
こうなってくると気になるのが、他の「属性を必要とする糖衣構文」です。
ということで省略可能引数は…?
あれ…?普通に使えました。
省略可能引数って OptionalAttribute
属性が必要では…?
なんと、OptionalAttribute クラスは .NET1.0 から含まれていました。
ΩΩΩ<な、なんだってー!?
VB.net では古くから省略可能引数がサポートされていたからなんですね。
次に dynamic。
public static class Hoge
{
public static void Fuga(this string a, int b = 0, dynamic c = null)
{
}
}
はい。拡張メソッドと一緒です。
System.Runtime.CompilerServices.DynamicAttribute
クラスを定義してやると…
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public sealed class DynamicAttribute : Attribute
{
}
おぉ、呼び出せました。
拡張メソッドに比べたら「どうしても dynamic を使いたい!」という場面は少ないと思いますが、覚えておいて損はないのではないでしょうか。
ついでに気になったので確認してみたところ、自作属性によって定義された拡張メソッドや dynamic を含む .NET2.0 の DLL を .NET3.5 以上がターゲットのプロジェクトから参照してみてもきちんと使えるのですね。
既にライブラリも(追記)
会社の先輩から既にライブラリがあることを教えて頂きました。
また、直後に Twitter でもタイムリーなネタが…
Func<T, TResult>とかも自分で定義すればよかったんですね…! / “C# 3.0 による .NET 2.0 アプリケーション開発 - XNA で LINQ を使おう - NyaRuRuの日記” http://t.co/FMdi8OJvV9
— 西村俊佑 (@nissuk) 2014, 3月 2
結構いまさらなネタだったんですねw
CallerMemberInfo (2014/05/09 追記)
ちなみに CallerMemberNameAttribute
クラスを自前で定義した .NET4.0 のプロジェクトで以下のメソッドを作ってみたところ、メンバー名は渡ってきませんでした。残念。
public new void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
// Livet の ViewModel.RaisePropertyChanged を呼び出す
base.RaisePropertyChanged(propertyName);
}