Wichtige Änderungen in Visual C# 2010

In der folgenden Tabelle sind wichtige Änderungen in Visual C# 2010 aufgeführt, die dazu führen können, dass eine in Visual C# 2008 erstellte Anwendung nicht kompiliert wird oder sich ihr Laufzeitverhalten ändert.

Kategorie

Problem

Beschreibung

Assemblybindung

Die Assemblybindung behandelt zwei Assemblys als äquivalent.

C# 2010-Anwendungen, die zur gleichen Zeit sowohl auf die .NET Framework-Version als auch auf die .NET Framework for Silverlight-Version einer bestimmten Verweisassembly verweisen und außerdem extern alias verwenden, können Compilerfehler verursachen. Standardmäßig behandelt die Assemblybindung die zwei Assemblys als äquivalent.

Um den Fehler zu beheben, geben Sie mit der /appconfig-Compileroption den Speicherort einer app.config-Datei an, die das Standardverhalten mit einem <supportPortability>-Tag deaktiviert. Weitere Informationen finden Sie unter /appconfig (C#-Compileroptionen).

Wenn Sie eine Anwendung mit Microsoft Build Engine (MSBuild) erstellen, fügen Sie der CSPROJ-Datei das entsprechende Tag hinzu.

Kovarianz und Kontravarianz

Für generische Schnittstellen und Delegaten, z. B. IEnumerable<T> und Func<TResult>, wurde eine neue implizite Konvertierung hinzugefügt.

Generische Schnittstellen und Delegaten, z. B. IEnumerable<T> und Func<TResult>, verfügen jetzt über eine implizite Konvertierung für generische Typargumente. Beispielsweise kann in C# 2010 IEnumerable<string> implizit in IEnumerable<object> konvertiert werden, und dies kann in den folgenden Szenarien unterschiedliches Verhalten verursachen.

Weitere Informationen finden Sie unter Kovarianz und Kontravarianz (C# und Visual Basic).

NULL-Sammeloperator

Der NULL-Sammeloperator (??) lässt lokale Variablen ohne Zuweisung nicht zu.

In C# 2010 sind nicht zugewiesene lokale Variablen als Operanden auf der rechten Seite des NULL-Sammeloperators nicht zulässig, auch wenn sichergestellt ist, dass der Operand auf der linken Seite nicht NULL ist.

Beispielsweise wird der folgende Code in C# 2008 kompiliert, erzeugt jedoch in C# 2010 Compilerfehler CS0165.

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

Typrückschluss für Methodengruppen

Der Compiler kann für Methodengruppen generische und nicht generische Delegaten ableiten, und dies kann zu Mehrdeutigkeit führen.

In C# 2008 kann der Compiler keine generischen Delegaten für Methodengruppen ableiten. Deshalb verwendet er immer einen nicht generischen Delegaten, sofern vorhanden.

In C# 2010 werden für Methodengruppen sowohl generische als auch nicht generische Delegaten abgeleitet, und der Compiler leitet mit gleicher Wahrscheinlichkeit generische oder nicht generische Delegaten ab. Dies kann zu Mehrdeutigkeit führen, wenn eine generische und eine nicht generische Version eines Delegaten vorhanden sind und beide Versionen die Anforderungen erfüllen. Beispielsweise wird in C# 2008 der folgende Code kompiliert, und der Code ruft eine Methode auf, die einen nicht generischen Delegaten verwendet. In C# 2010 erzeugt dieser Code einen Compilerfehler aufgrund eines mehrdeutigen Aufrufs.

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);
    }
}

Optionale Parameter

In C# wird jetzt das OptionalAttribute erkannt. Dies verursacht möglicherweise Änderungen bei der Auflösung von Methodenüberladungen.

In C# 2008 wird das OptionalAttribute vom Compiler ignoriert, da C# keine optionalen Parameter unterstützt.

In C# 2010 werden optionale Parameter unterstützt. Sie können optionale Parameter mit der neuen Sprachsyntax oder mit OptionalAttribute deklarieren. Wenn Sie in C# 2008 OptionalAttribute für die Interoperabilität mit anderen Sprachen verwenden, die optionale Parameter unterstützen (z. B. Visual Basic), wählt C# 2008 immer nur Methoden aus, die über alle im Methodenaufruf aufgeführten Parameter verfügen. In C# 2010 wird möglicherweise eine Methode gewählt, die über optionale Parameter verfügt, auch wenn diese Parameter nicht im Methodenaufruf angegeben werden.

Der folgende Code ruft eine Methode einer Basisklasse in C# 2008 auf, da ein optionales Attribut ignoriert wird, und der Compiler verhält sich wie bei einer Methode der abgeleiteten Klasse, die immer einen Zeichenfolgenparameter erfordert. In C# 2010 ruft der Code eine Methode in einer abgeleiteten Klasse auf, da diese Methodensignatur jetzt dem Methodenaufruf entspricht.

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

Weitere Informationen finden Sie unter Benannte und optionale Argumente (C#-Programmierhandbuch).

Eingebettete Interoptypen

Der Versuch, mit CoClass eine Instanz eines eingebetteten COM-Typs zu erstellen, führt zu einem Compilerfehler.

Wenn Sie in C# 2010 einen Verweis auf eine Interopassembly, z. B. Microsoft.Office.Interop.Word oder Microsoft.Office.Interop.Excel, hinzufügen, werden die Typen aus dieser Assembly eingebettet. Weitere Informationen finden Sie unter Exemplarische Vorgehensweise: Einbetten von Typen aus verwalteten Assemblys (C# und Visual Basic) und /link (C#-Compileroptionen).

Wenn Sie im Code eine Instanz eines eingebetteten COM-Typs erstellen, müssen Sie die Instanz mit der entsprechenden Schnittstelle erstellen. Wenn Sie versuchen, mit der CoClass eine Instanz eines eingebetteten COM-Typs erstellen, meldet der Compiler einen Fehler.

// 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();

Eingebettete Interoptypen

Die get_-Methode und die set_-Methode können nicht auf indizierte Eigenschaften zugreifen.

Wenn Sie COM-Typen einbetten, werden alle Aufrufe von COM-Objekten dynamisch verteilt. Wenn Sie versuchen, mit der get_Range-Methode auf einen indizierten Eigenschaften-Range zuzugreifen, sucht der C#-Laufzeitbinder die benutzerdefinierte get_Range-Methode in der Klasse, und diese Methode ist nicht vorhanden. Dies wird im folgenden Codebeispiel veranschaulicht. Um dieses Problem zu vermeiden, verwenden Sie die Syntax von C# 2010 für indizierte Eigenschaften. Weitere Informationen finden Sie unter Gewusst wie: Zugreifen auf Office-Interop-Objekte mithilfe von Visual C# 2010-Funktionen (C#-Programmierhandbuch).

// 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]];

Ereignissynchronisierung

Die Synchronisierung zum Schreiben in das dahinter liegende Feld eines Ereignisses in den vom Compiler generierten Methoden zum Hinzufügen und Entfernen erfolgt jetzt mit der CompareExchange-Methode. Dies kann eine Racebedingung verursachen.

In C# 2010 erfolgt die Synchronisierung zum Ändern des dahinter liegenden Felds für die vom Compiler generierten Methoden zum Hinzufügen und Entfernen mit der CompareExchange-Methode statt mit MethodImplAttribute.

Dies kann Racebedingungen verursachen, die in C# 2008 nicht aufgetreten sind, wie im folgenden Codebeispiel gezeigt.

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() { }
}

Um die Racebedingung zu vermeiden, ändern Sie die Loop-Methode wie im folgenden Codebeispiel gezeigt.

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();
           }
        }
    }
}

Siehe auch

Weitere Ressourcen

Erste Schritte mit Visual C#

MSBuild