Visual C# 2010 の互換性に影響する変更点

次の表に示す Visual C# 2010 の変更点により、Visual C# 2008 で作成されたアプリケーションがコンパイルできなくなる、または実行時の動作が変わる可能性があります。

カテゴリ

懸案事項

説明

アセンブリ バインディング

アセンブリ バインディングで 2 つのアセンブリが同等に扱われる。

C# 2010 アプリケーションで、特定の参照アセンブリの .NET Framework バージョンと .NET Framework for Silverlight バージョンを同時に参照し、extern alias を使用していると、コンパイラ エラーが発生します。 既定では、アセンブリ バインディングでこの 2 つのアセンブリは同等に扱われます。

このエラーを解決するには、/appconfig コンパイラ オプションを使用して、<supportPortability> タグで既定の動作を無効にする app.config ファイルの場所を指定します。 詳細については、「/appconfig (C# コンパイラ オプション)」を参照してください。

Microsoft Build Engine (MSBuild) を使用してアプリケーションをビルドする場合は、適切なタグを .csproj ファイルに追加します。

共変性と反変性

IEnumerable<T>Func<TResult> などのジェネリック インターフェイスおよび汎用デリゲート用に新しい暗黙の型変換が追加された。

IEnumerable<T>Func<TResult> などのジェネリック インターフェイスおよび汎用デリゲートで、ジェネリック型引数の暗黙の型変換が行われるようになりました。 たとえば、C# 2010 では、IEnumerable<string> を IEnumerable<object> に暗黙的に変換できます。そのため、次のシナリオで異なる動作が発生します。

詳細については、「共変性と反変性 (C# および Visual Basic)」を参照してください。

null 合体演算子

null 合体演算子 (??) で未割り当てのローカル変数を使用できない。

C# 2010 では、null 合体演算子の左側のオペランドが null でないことが保証されていても、未割り当てのローカル変数を右側のオペランドとして使用することはできません。

たとえば、次のコードは C# 2008 ではコンパイルされますが、C# 2010 ではコンパイラ エラー CS0165 が生成されます。

int? i;
int? j;
int? x = (i = 2) ?? j;

メソッド グループの型の推論

コンパイラは、メソッド グループの汎用デリゲートと非汎用デリゲートの両方を推論できるため、あいまいさが生じる場合がある。

C# 2008 では、コンパイラはメソッド グループの汎用デリゲートを推論できません。 そのため、デリゲートが存在する場合は常に非汎用デリゲートが使用されます。

C# 2010 では、メソッド グループの汎用デリゲートと非汎用デリゲートの両方が推論されます。コンパイラは、どちらのデリゲートも同じ確率で推論します。 そのため、デリゲートの汎用バージョンと非汎用バージョンがあり、どちらも要件を満たしている場合は、あいまいさが生じる可能性があります。 たとえば、次のコードは C# 2008 ではコンパイルされ、非汎用デリゲートを使用するメソッドが呼び出されます。 C# 2010 でこのコードを使用すると、あいまいな呼び出しを報告するコンパイラ エラーが生成されます。

public class Sample
{
    delegate string NonGenericDelegate();
    delegate T GenericDelegate<T>();
    string UseDelegate(NonGenericDelegate del)
    {
        return null;
    }

    T UseDelegate<T>(GenericDelegate<T> del)
    {
       return default(T);
    }

    public string Test()
    {
       // This line produces 
       // a compiler error in C# 2010.
       return UseDelegate(Test);
    }
}

省略可能なパラメーター

C# で OptionalAttribute が認識されるようになったため、メソッド オーバーロードの解決法が変わる可能性がある。

C# 2008 では、C# が省略可能なパラメーターをサポートしていないため、コンパイラは OptionalAttribute を無視します。

C# 2010 では、省略可能なパラメーターが導入されています。 新しい言語構文または OptionalAttribute を使用して、省略可能なパラメーターを宣言できます。 省略可能なパラメーターをサポートする他の言語 (Visual Basic など) との相互運用性を確保するために C# 2008 で OptionalAttribute を使用した場合、C# 2008 ではメソッド呼び出しで示されているすべてのパラメーターを含むメソッドだけが常に選択されます。 C# 2010 では、メソッド呼び出しで省略可能なパラメーターが指定されていない場合でも、これらのパラメーターを含むメソッドが選択される可能性があります。

C# 2008 では、省略可能な属性は無視され、コンパイラは派生クラスのメソッドが常に文字列パラメーターを必要とする場合と同様に動作するため、次のコードでは基本クラスのメソッドが呼び出されます。 C# 2010 では、このメソッド シグネチャがメソッド呼び出しに対応するようになったため、派生クラスのメソッドが呼び出されます。

class Program
{
    public static void Main(string[] args)
    {
        var obj = new Derived();
        obj.Method();
    }
}

class Base
{
    public void Method() 
    { 
        Console.WriteLine(
            "Base class + no optional parameters"); 
    }
}

class Derived : Base
{
    public void Method(
        [Optional][DefaultParameterValue("Hello")] 
        string s) 
    { 
        Console.WriteLine(
            "Derived class + an optional parameter");
    }
}
// Prints different results.
// C# 2008: Base class + no optional parameters
// C# 2010: Derived class + an optional parameter

詳細については、「名前付き引数と省略可能な引数 (C# プログラミング ガイド)」を参照してください。

埋め込まれた相互運用機能型

CoClass を使用して埋め込み COM 型のインスタンスを作成しようとすると、コンパイラ エラーが発生する。

C# 2010 では、Microsoft.Office.Interop.WordMicrosoft.Office.Interop.Excel などの相互運用機能アセンブリへの参照を追加すると、このアセンブリから型が埋め込まれます。 詳細については、「チュートリアル: マネージ アセンブリからの型の埋め込み (C# および Visual Basic)」および「/link (C# コンパイラ オプション)」を参照してください。

コードで埋め込み COM 型のインスタンスを作成する場合は、適切なインターフェイスを使用してインスタンスを作成する必要があります。 CoClass を使用して埋め込み COM 型のインスタンスを作成しようとすると、コンパイラからエラーが報告されます。

// Add the following statement
// at the beginning of the file:
// using Word = Microsoft.Office.Interop.Word;
// This statement does not compile in C# 2010.
Word.Application wordClass = 
    new Word.ApplicationClass();
// Use the following code instead.
Word.Application wordInterface = 
    new Word.Application();

埋め込まれた相互運用機能型

get_ メソッドおよび set_ メソッドでインデックス付きプロパティにアクセスできない。

COM 型を埋め込んだ場合、COM オブジェクトのすべての呼び出しが動的にディスパッチされます。 次のコード例に示すように、get_Range メソッドを使用してインデックス付き Range プロパティにアクセスしようとすると、C# ランタイム バインダーはクラス内のユーザー定義の get_Range メソッドを探しますが、このメソッドは存在しません。 この問題を回避するには、インデックス付きプロパティに C# 2010 の構文を使用します。 詳細については、「方法: Visual C# 2010 の機能を使用して Office 相互運用オブジェクトにアクセスする (C# プログラミング ガイド)」を参照してください。

// Add the following statement
// at the beginning of the file:
// using Excel = Microsoft.Office.Interop.Excel;
Excel.Application excelApp = new Excel.Application();
excelApp.Visible = true;
excelApp.Workbooks.Add(
    Excel.XlWBATemplate.xlWBATWorksheet);
Excel.Worksheet sheet = 
    excelApp.ActiveSheet as Excel.Worksheet;
// The following statement throws 
// a run-time excpetion in C# 2010.
Excel.Range rangeOld = 
    sheet.get_Range(
        sheet.Cells[1, 1], sheet.Cells[2, 2]);
// Use the following syntax instead.
Excel.Range rangeNew = 
    sheet.Range[sheet.Cells[1, 1], 
                sheet.Cells[2, 2]];

イベントの同期

コンパイラが生成した追加メソッドおよび削除メソッドでのイベントのバッキング フィールドへの書き込みの同期が CompareExchange メソッドを使用して行われるようになった。 これにより、競合状態が発生する場合がある。

C# 2010 では、コンパイラが生成した追加メソッドと削除メソッドでのバッキング フィールドの変更の同期は、MethodImplAttribute ではなく CompareExchange メソッドを使用して行われます。

これにより、次のコード例に示すように、C# 2008 では発生しなかった競合状態が発生する場合があります。

using System;
using System.Threading;

class Sample
{
    public event Action sampleEvent;

    static void Main()
    {
        new Sample().Loop();
    }

    void Loop()
    {
        new Thread(() => Test.Method(this)).Start();
        while (true)
        {
            lock (this)
            {
                if (sampleEvent != null)
                {
                    // In C# 2010, sampleEvent 
                    // can be null here,
                    // which causes 
                    // a run-time exception.
                    sampleEvent();
                }
            }
        }
    }
}

class Test
{
    public static void Method(Sample arg)
    {
        while (true)
        {
            arg.sampleEvent += Method;
            arg.sampleEvent -= Method;
        }
    }
    static void Method() { }
}

競合状態を回避するには、次のコード例に示すように Loop メソッドを変更します。

void Loop()
{
   new Thread(() => Test.Method(this)).Start();
   while (true)
   {
       lock (this)
       {
           // Create a local copy of the delegate.
           Action local = sampleEvent;
           if (local != null)
           {
               local();
           }
        }
    }
}

参照

その他の技術情報

Visual C# について

MSBuild