C#の言語バージョンと.NET Frameworkバージョン
C#の言語機能のバージョンと.NET Frameworkのバージョン(実行環境には大して手が入っていないので、おおむね標準ライブラリのバージョンのこと。どのクラス・どのメソッドが使えるか)は、基本的には独立しています。なので、C#の新機能の多くは古い.NET Framework上でも動きます。
「多くは」であって、「全て」ではないわけですが。ここが今日の主題。どういう機能は、どういう理由で動かないか。どうやっても動かないのか、それとも、動かしようがあるのか。ということについて書いていきます。
サンプルコードはこちらに: https://github.com/ufcpp/UfcppSample/tree/master/LanguageAndFrameworkVersion
古いバージョンで動くかどうか
.NET Framework 1.0/1.1 はもうサポートが切れているので調査対象外(Visual Studio上でもターゲット フレームワークに選べないので)。つまり、以下の表で、「2.0で動く」となっているものは「どこでも動くもの」。
C# 3.0
Visual Studio 2008, .NET Framework 3.5と同時期リリース。
機能 |
どのバージョンで動くか |
変数の型推論 |
2.0 |
配列の型推論 |
|
オブジェクト初期化子 |
|
コレクション初期化子 |
|
プロパティの自動実装 |
|
ラムダ式 |
|
クエリ式 † |
|
部分メソッド |
|
匿名型 |
|
拡張メソッド |
3.5※ |
※ … 2.0で動かすすべあり
† … 補足あり
C# 4.0
Visual Studio 2010, .NET Framework 4と同時期リリース。
機能 |
どのバージョンで動くか |
引数の規定値と名前付き引数 |
2.0 |
変性(genericのin/out型注釈)† |
|
dynamic |
4.0× |
† … 補足あり
× … dynamicは古いバージョンの.NET Frameworkで動かすのがほぼ無理臭い唯一の機能かも。
C# 5.0
Visual Studio 2012, .NET Framework 4.5と同時期リリース。
機能 |
どのバージョンで動くか |
async/await |
4.5 ※1 |
Caller Info |
4.5 ※2 |
※1 … 4で動かすすべあり
※2 … 2.0で動かすすべあり
C# 6.0
おそらくVisual Studio 2015, .NET Framework 4.6と同時期リリース予定。
機能 |
どのバージョンで動くか |
自動実装プロパティに対する初期化子 |
2.0 |
get-onlyの自動実装プロパティ |
|
式形式の関数メンバー定義 |
|
using static |
|
null条件演算子 |
|
インデックス初期化子 |
|
nameof演算子 |
|
例外フィルター |
|
構造体の引数なしコンストラクター |
|
文字列補間 |
2.0 ※1 |
拡張メソッドを使ったコレクション初期化子 |
3.5 ※2 |
catch句/finally句内でのawait演算子利用 |
4.5 ※3 |
※1 … 書き方によっては4.6でないと動かなくなる
※2 … 拡張メソッドの制限そのまま。拡張メソッドを2.0で動かす方法はあるので、それを使えば2.0
※3 … 同様に、await演算子の制限。4で動かすすべあり
動かし方、補足など
前節の表で、2.0で動くとなっているものは、要は、ライブラリ依存がなくて、単純にC#コンパイラーだけの仕事で実現できる機能です。
逆に、特定のバージョンに依存しているものは、そのバージョンで追加されたクラスに依存しています。
なのに、古いバージョンの.NET Frameworkでも「動かすすべがある」というのはどういうことかというと、あるクラスに依存するといっても厳密なチェックをしているわけではなく、同じ名前・同じ機能のクラスを自前で実装すれば動きます。なので、原理的に言うと、どの機能でも.NET Framework 2.0で動かせるんですが… C#機能ごとに、その依存するクラスを実装する大変さが全然違うので、現実的には全部とはいかないでしょう。
拡張メソッド、Caller Info
かなり簡単なのがこの2つ。この2つは、単にメソッドや引数に属性が付くだけのものです。
- 拡張メソッド → ExtensionAttribute(System.Runtime.CompilerServices名前空間)
- Caller Info → CallerFilePathAttribute, CallerLineNumberAttribute, CallerMemberNameAttribute(System.Runtime.CompilerServices名前空間)
属性の実装は簡単。例えば以下のようなコードで終わり。
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
public
sealed
class
ExtensionAttribute : Attribute
{
}
}
クエリ式
System.Linq名前空間のクラスがなくて動くの?と一瞬思うかもしれませんが、SelectとかWhereとかを自前実装すれば使えます。そんなに難易度も高くないものなので割とちょろい。
あと、SelectとかWhereは、普通のインスタンス メソッドでも拡張メソッドでもどちらでもOKです。
変性(genericのin/out型注釈)
インターフェイスやデリゲートを定義する側は何の問題もなく、.NET Framework 3.5以前の上で動くんですが…
残念なのは、標準ライブラリ(BCL: Base Class Library)中のクラスにちゃんとした変性注釈がついたのは.NET Framework 4からです。つまり、以下のようなコードを書けるのは、結局、.NET Framework 4以降のみ。
List<string> x = new
List<string> { “one”, “two”, “three” };
IEnumerable<object> y = x;
dynamic
dynamicが使っているのはSystem.Dynamic名前空間以下のクラスなんですが… こいつの自前実装はさすがにちょっと…
実質的に、古い.NET Framework上で動かしようがない唯一の機能かも。もちろん、monoの実装をとってきて使うなどすれば、無理ではないはず。
async/await
これも、.NET Framework 4.5で入ったTaskクラスに対する拡張が必須になります。自前で実装できる規模も超えていると思います。
ただ、こちらには多少救いがあって、マイクロソフトの.NETチームは、.NET 4と.NET 4.5の差分にあたるものを、NuGetパッケージとして公開してくれています。その中にはasync/awaitに関するものもあって、Microsoft.Bcl.Asyncという名前のパッケージになっています。これを使えば、async/awaitを.NET Framework 4の上で動かすことはできます。しかし、あくまで4から4.5の間の差分で、3.5以前には対応できません。
文字列補間(string interpolation)
(現行のVisual Studio 2015 Previewとは文法が変わることが確定しているんですが、新しい方の(今は動かない)文法で説明します)
文字列補間は、普通に使う分にはただのstring.Formatへの展開なので、.NET Framework 2.0上でも動きます。
var s = $”{x}, {y}”;
このsはstring型で、この行は以下のように展開されます。
var s = string.Format(“{0}, {1}”, x, y);
ただ、この文法だとカルチャー指定付きでのFormatなどができないので、別途、以下のように書けるバージョンが追加される予定です。
IFormattable f = $“{x}, {y]”;
この場合、以下のように展開されます。
IFormattable f = new System.Runtime.CompilerServices.FormattedString(“{0}, {1}”, x, y);
この、FormattedStringクラスは、.NET Framework 4.6で追加される予定のクラスです。それほど複雑ではなく、自作は簡単でしょう。以下のような内容です。
namespace System.Runtime.CompilerServices
{
public
struct
FormattedString : System.IFormattable
{
private
readonly
String format;
private
readonly
object[] args;
public FormattedString(String format, params
object[] args)
{
this.format = format;
this.args = args;
}
public
String Format => this.format;
public
object[] Args => this.args;
string
IFormattable.ToString(string ignored, IFormatProvider formatProvider)
{
return
String.Format(formatProvider, format, args);
}
}
}
また、おそらくは、async/awaitと同様に、古い.NET Frameworkを対象としたNuGetパッケージが提供されるものと思われます。
あれこれ書きましたが
まあ、さすがに最近、.NET Framework 2.0案件の話は聞くこと減って来たかなぁ…
Windows 7/Windows Server 2008 R2の標準インストールでのバージョンが.NET Framework 3.5.1なので、割かし、最低ラインがここ。また、Windows 8/Windows Server 2012の場合は.NET Framework 4.5。なので、3.5と4.5の場合だけ大まかに覚えておけばいいと思います。
- .NET Framework 3.5 = Windows 7 … async/awaitとdynamic以外は平気(Caller Infoだけ、やりよう次第)
- .NET Framework 4.5 = Windows 8 … 全部平気
ということで、今日書いた内容、実質的に「Windows Server 2003 R2をまだお使いの方、かつ、サーバー側開発なのになぜか.NET Frameworkのバージョンを2.0から上げれない方」を対象にした非常にニッチな話な気もしつつ。
一応、言語のバージョンとフレームワークのバージョンの関係性の説明ということで。
コメントを残す