Modifications importantes dans Visual C# 2008

Mise à jour : Juillet 2008

Modifications importantes dans Visual C# 2008 Service Pack 1

Le tableau suivant répertorie toutes les modifications importantes dans Visual C# 2008 Service Pack 1 qui peuvent concerner une application créée dans la version Release d'origine de Visual C# 2008 ou dans Visual C# 2005.

Numéro de modification

Catégorie

Problème

Description

1

Résolution de surcharge

L'inférence de type est maintenant incluse sur les tableaux de types pointeur dans la résolution de surcharge de méthode.

Dans Visual C# 2008 et versions antérieures, l'inférence de type fait en sorte que les tableaux de types pointeur soient exclus du processus de résolution de surcharge de méthode. Dans le code suivant, le compilateur Visual C# 2005 sélectionne la version non générique de Test car la version générique de Test n'est pas prise en considération à cause de son paramètre de type int*[]. Dans Visual C# 2008, la version générique de Test est sélectionnée.

using System.Collections.Generic;
unsafe class Program
{
    static void Main()
    {
        IEnumerable<int*[]> y = null;
        Test(y); 
    }
// Selected by Visual C# 2008.
    static void Test<S>(IEnumerable<S> x) { } // Selected by Visual C# 2005.
    static void Test(object o) { } 
}

2

Indexeurs

Le compilateur génère maintenant l'erreur CS0466 pour les indexeurs et les propriétés en plus des méthodes.

Dans la version Release d'origine de Visual C# 2008 et versions antérieures, il est possible de définir une implémentation explicite d'un indexeur où l'implémentation a un paramètre params mais la définition d'interface n'en a pas. Cette construction est contraire à la spécification. Dans Visual C# 2008 SP1, cette construction génère Erreur du compilateur CS0466, comme illustré dans le code suivant.

interface I
{
    int this[int[] p] { set; }
}
class Base : I
{
// Produces CS0466:
    int I.this[params int[] p]    {
        set
        {
        }
    }

}

3

Types nullables et expressions ??

Le compilateur évalue maintenant correctement les expressions dans lesquelles des variables nullables sont comparées à elles-mêmes.

Dans la version Release d'origine de Visual C# 2008, le code suivant est compilé et génère la valeur « false » au moment de l'exécution. Dans Visual C# 2008 Service Pack 1, Avertissement du compilateur (niveau 3) CS1718 est produit et la valeur « false » est générée.

static class Program
{
    static void Main()
    {
        int? x = null;
        bool y = x == x;
        Console.WriteLine(y);
    }
}

4

try-finally dans les itérateurs

L'exécution de blocs finally imbriqués à partir d'itérateurs qui ont des instructions break est modifiée.

Dans la version Release d'origine de Visual C# 2008, le code suivant exécute les finally externes à deux reprises. Dans Visual C# 2008 SP1, le finally externe est exécuté une fois.

using System;
using System.Collections;
using System.Collections.Generic;
public class Test
{
    public static void Main()
    {
        Console.WriteLine("in main");
        foreach (int i in GetInts())
        {
            Console.WriteLine("in foreach");
            break; 
        }
    }
    static IEnumerable<int> GetInts()
    {
        Console.WriteLine("in GetInts");
        while (true)
        {
            Console.WriteLine("in while");
            try
            {
                Console.WriteLine("in outer try");
                try
                {
                    Console.WriteLine("in inner try before yield");
                    yield return 1;
                    Console.WriteLine("in inner try after yield");
                    break;
                }
                finally
                {
                    Console.WriteLine("in inner finally");
                }
            }
            finally
            {
                Console.WriteLine("in outer finally");
            }
        }
    }
}

5

Arborescences d'expression

La conversion boxing incorrecte d'expressions de méthode dans les arborescences d'expression ne se produit plus.

Dans la version Release d'origine de Visual C# 2008, le code suivant génère 7, 0. La ligne Console.WriteLine(e.Compile()(default(T))); génère zéro car S est converti incorrectement. Dans Visual C# 2008 SP1, aucune conversion boxing ne se produit et le programme génère 7, 7.

using System;
using System.Linq;
using System.Linq.Expressions;
class Program
{
    static void Main()
    {
        Test<S>();
    }
    static void Test<T>() where T : I
    {       
        Expression<Func<T, int>> e = x => x.SetX() + x.X;
// No boxing in SP1:
        Console.WriteLine(e.Compile()(default(T))); 
    }
}
interface I
{
    int X { get; }
    int SetX();
}
struct S : I
{
    public int X { get; private set; }
    public int SetX()
    {
        X = 7;
        return 0;
    }
}

6

Initialiseurs d'objets

L'initialisation des types valeur dans les initialiseurs d'objets a été corrigée.

Dans la version Release d'origine de Visual C# 2008, la variable locale b dans l'exemple suivant n'est pas initialisée correctement et son membre X a une valeur de zéro. Dans Visual C# 2008 SP1, S.X est initialisée correctement à 1 dans les deux expressions new.

using System;
using System.Linq;
using System.Linq.Expressions;
    class Program
    {
        static void Main()
        {
            Test<S>();
        }
        static void Test<T>() where T : I, new()
        {
            var a = new T();
            a.X = 1;
            Console.WriteLine(a.X);
            var b = new T { X = 1 };
            Console.WriteLine(b.X);
        }
    }
    interface I
    {
        int X { get; set; }
    }
    struct S : I
    {
        public int X { get; set; }
    }
// Original release version of Visual C# 2008 output: 1 0
// Visual C# 2008 SP1 output: 1 1

7

Conversions de types

Les littéraux Null ne sont plus convertibles en valeurs enum.

Dans la version Release d'origine de Visual C# 2008, les littéraux Null sont dans certains cas autorisés à être convertis en valeurs enum. Dans Visual C# 2008 SP1, Erreur du compilateur CS1502 et Erreur du compilateur CS1503 sont générées si vous essayez d'effectuer cette conversion, comme illustré dans l'exemple suivant.

enum MyEnum
{
    Zero = 0,
    One = 1
}
class MyClass { }
class Program
{
    static void Main(string[] args)
    {
// Produces CS1502 and CS1503:
        Test((MyClass)null);         }
    static void Test(MyEnum x)
    {
        System.Console.WriteLine(x);
    }
}

8

Arborescences d'expression

Une arborescence d'expression non valide lève maintenant l'exception correcte.

Dans la version Release d'origine de Visual C# 2008, une arborescence d'expression qui contient un appel de méthode à une méthode qui n'est pas sur le type spécifié lève une System.Security.VerificationException. Dans Visual C# 2008 SP1, une System.ArgumentException est levée, comme illustré dans le code suivant.

using System;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
class Program
{
    public struct S { }
    static void Main()
    {
        Type t = typeof(System.Enum);
        MethodInfo m = t.GetMethod("GetTypeCode");
        ParameterExpression p = Expression.Parameter(typeof(S), "s");
        Expression<Func<S, TypeCode>> e = Expression.Lambda<Func<S, TypeCode>>(
// Throws System.ArgumentException in Visual C# 2008 SP1:
            Expression.Call(p, m), p); 
        Func<S, TypeCode> f = e.Compile();
// Throws System.Security.VerificationException in the
// original release version of Visual C# 2008: 
        Console.WriteLine(f(new S())); 
    }
}

9

Attributs

CharSet.Unicode est maintenant propagé aux types d'assistance générés par C# pour les champs de tableaux fixes.

Le compilateur C# génère des types d'assistance pour encapsuler les tableaux fixes. Dans la version Release d'origine de Visual C# 2008 et versions antérieures, la disposition du tableau est toujours ANSI, même si l'attribut StructLayout spécifie CharSet.Unicode. Il n'existe aucun moyen de modifier cela dans le code source C#. Dans Visual C# 2008 SP1, la valeur CharSet spécifiée dans l'attribut StructLayout est utilisée pour construire la classe d'assistance, comme illustré dans le code suivant.

using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
unsafe struct Test
{
    public fixed char Chars[8];
}
class Program
{
    static void Main(string[] args)
    {
    }
}
Original release version of Visual C# 2008 MSIL:
.class sequential ansi sealed nested public beforefieldinit '<Chars>e__FixedBuffer0'
       extends [mscorlib]System.ValueType
{
  // ... 
} // end of class '<Chars>e__FixedBuffer0'
Visual C# 2008 SP1 MSIL:
.class sequential unicode sealed nested public beforefieldinit '<Chars>e__FixedBuffer0'
       extends [mscorlib]System.ValueType
{
  // . . . 
} // end of class '<Chars>e__FixedBuffer0'

10

Vérification de dépassement de capacité

stackalloc exécute maintenant une vérification de dépassement de capacité.

Dans la version Release d'origine de Visual C# 2008, il est possible qu'une allocation stackalloc échoue sans provoquer d'exception. Cela est dû à une instruction mul non contrôlée dans le code MSIL (Microsoft Intermediate Language) lorsque la longueur du tableau est multipliée par la taille de chaque élément. Dans Visual C# 2008 SP1, une instruction mul.ovf est générée au lieu d'une instruction mul ; les dépassements de capacité génèrent par conséquent une System.OverflowEx ception lorsque l'allocation est tentée au moment de l'exécution.

class Program
{
    static void Main(string[] args)
    {
        int var = 0x40000000;
        unsafe
        {
            // 0x40000000 * sizeof(int) does not fit in an int.
            int* listS = stackalloc int[var]; 
// Visual C# 2008 SP1: System.OverflowException.
            listS[0] = 5; 
// Original release version of Visual C# 2008: 
// System.NullReferenceException.
        }
    }
}

11

Opérateurs de requête standard

Les requêtes sur des collections non génériques utilisent maintenant la sémantique de conversion C# standard.

Dans les expressions de requête LINQ sur des collections non génériques telles que System.Collections.ArrayList, la clause from de la requête est réécrite par le compilateur de façon à inclure un appel à l'opérateur Cast<T>. Cast<T> convertit tous les types d'éléments au type spécifié dans la clause from dans la requête. De plus, dans la version Release d'origine de Visual C# 2008, l'opérateur Cast<T> exécute également certaines conversions de type valeur et conversions définies par l'utilisateur. Toutefois, ces conversions sont exécutées en utilisant la classe System.Convert au lieu de la sémantique C# standard. Elles provoquent également des problèmes de performances significatifs dans certains scénarios. Dans Visual C# 2008 SP1, l'opérateur Cast<T> a été modifié de façon à lever une InvalidCastException pour les conversions de type valeur numérique et les conversions définies par l'utilisateur. Cette modification élimine à la fois la sémantique de conversion C# non standard et le problème de performances. L'exemple de code suivant en fournit une illustration.

using System;
using System.Linq;
class Program
{
    public struct S { }
    static void Main()
    {
        var floats = new float[] { 2.7f, 3.1f, 4.5f };
        var ints = from int i in floats 
                   select i;
// Visual C# 2008 SP1 throws InvalidCastException. 
        foreach (var v in ints) 
            Console.Write("{0} ", v.ToString());
        // The original release version of Visual C# 2008
        // compiles and outputs 3 3 4
    }
}

Modifications importantes dans la version Release d'origine de Visual C# 2008

Le tableau suivant répertorie toutes les modifications importantes dans la version Release d'origine de Visual C# 2008 qui peuvent empêcher la compilation d'une application créée dans Visual C# 2005 ou qui peuvent modifier son comportement au moment de l'exécution.

Numéro de modification

Category

Problème

Description

12

Conversions de types

La conversion de toute expression constante avec une valeur de zéro en enum est maintenant autorisée.

Un littéral 0 est implicitement convertible en tout type enum. Dans les versions Visual C# 2005 et antérieures du compilateur, il existe également certaines expressions constantes qui sont évaluées à 0 et qui peuvent être converties implicitement en tout type enum, mais la règle qui détermine lesquelles de ces expressions sont convertibles est vague. Dans Visual C# 2008, toutes les expressions constantes qui sont égales à 0 peuvent être converties implicitement en tout type enum.

Cela pourrait provoquer des modifications dans le comportement du code existant, tel que la résolution de surcharge de méthode qui repose sur l'absence de cette conversion implicite. Le code suivant est compilé avec succès sur les compilateurs Visual C# 2005 et versions antérieures ; il résout l'appel de méthode sur la valeur courte uniquement à la surcharge int. Dans Visual C# 2008, cet appel est ambigu car la valeur courte est également implicitement convertible en E. Dans Visual C# 2008, le comportement est modifié de façon à autoriser la conversion de toute expression constante évaluée à zéro.

public enum E
{
    Zero = 0,
    One = 1,
} 
class A
{
    public A(string s, object o)
    { System.Console.WriteLine("{0} => A(object)", s); } 
    public A(string s, E e)
    { System.Console.WriteLine("{0} => A(Enum E)", s); }
} 
class B
{
    static void Main()
    {
        A a1 = new A("0", 0);
        A a2 = new A("1", 1);
        A a3 = new A("(int) E.Zero", (int) E.Zero);
        A a4 = new A("(int) E.One", (int) E.One);
    }
}
Visual C# 2005 output:
0 => A(Enum E)
1 => A(object)
(int) E.Zero => A(object)
(int) E.One => A(object)
Visual C# 2008 output:
0 => A(Enum E)
1 => A(object)
(int) E.Zero => A(Enum E)
(int) E.One => A(object)

13

Attributs

Une erreur se produit maintenant lorsque le même attribut TypeForwardedTo est présent à deux reprises dans un assembly.

Dans Visual C# 2005, aucune erreur n'est générée si un assembly contient deux attributs System.Runtime.CompilerServices.TypeForwardedTo qui ciblent le même type. Dans Visual C# 2008, une Erreur du compilateur CS0739 est générée, comme le montre l'exemple suivant.

// Class1.cs
// Causes CS0739:
    [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(Test))]
    [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(Test))] 
    public class Test
    {
        public static int Main()
        {
            Test f = new Test();
            return f.getValue();
        }
    }
    // Library1.cs
    public class Test
    {
        public int getValue()
        {
            return 0;
        }

}

14

Erreurs de type

Un nouvel avertissement relatif à l'utilisation d'un membre de type référence dans un struct a été ajouté.

Les règles d'assignation définie pour les structs requièrent que le struct soit défini à une instance existante de son type ou que chacun de ses membres soit attribué avant d'être référencé. Dans Visual C# 2005, aucun avertissement ou erreur n'est généré lorsqu'un membre de type référence non assigné d'un struct est utilisé. Dans Visual C# 2008, une Avertissement du compilateur (niveau 1) CS1060 est générée, comme le montre l'exemple suivant.

    public class U { public int i;}
    public struct T { public U u;}
    class Program
    {
        static void Main()
        {
            T t;
// Produces CS1060:    
            t.u.i = 0; 
        }
    }

15

Vérification de dépassement de capacité

Le contrôle de plage sur les types décimaux const a été corrigé.

Dans Visual C# 2005, lorsque vous effectuez un cast de types décimaux const, le contrôle de plage n'est pas toujours correct et des erreurs de compilation incorrectes peuvent être générées. Dans Visual C# 2008, le code suivant génère l'erreur correcte : Erreur du compilateur CS0031.

        static void Main()
        {
            const decimal d = -10m;
            unchecked
            {
                const byte b = (byte)d; //CS0031
            }
        }

16

Vérification de dépassement de capacité

Les conversions hors limites en long génèrent maintenant l'erreur de compilation correcte.

Dans Visual C# 2005, le code suivant ne génère pas d'erreur de compilation. Dans Visual C# 2008, il génère l'Erreur du compilateur CS0031.

class Conversion 
    {
        static void Main() 
        {
            long l2 = (long) 9223372036854775808M; //CS0031 
        }
    }

17

Mémoires tampons de taille fixe

L'accès à une mémoire tampon de taille fixe dans un struct non sécurisé avant l'attribution d'une valeur à la mémoire tampon génère maintenant une erreur de compilation.

Les règles d'assignation définie pour les pointeurs non sécurisés requièrent que le pointeur soit défini avant son déréférencement. Dans Visual C# 2005, lorsqu'un struct non sécurisé contient un pointeur vers un tableau, l'accès au pointeur avant de lui attribuer une valeur ne générait pas d'erreur de compilation. Dans Visual C# 2008, cela génère une Erreur du compilateur CS0165, comme illustré dans le code suivant.

    unsafe class Test
    {
        static void Main()
        {
            S* ps;
            ps->i[0]++;        } // CS0165
    }
    unsafe struct S
    {
        public fixed int i[10];
    }

18

Les effets secondaires sont maintenant conservés dans les expressions de fusion Null.

Assignation définie et opérateur ??.

Dans Visual C# 2005, dans certains scénarios, les effets secondaires sur la partie gauche d'une expression de fusion Null ne sont pas conservés. Dans ces cas-là, la deuxième instruction Console.WriteLine dans l'exemple suivant génère une erreur de compilation incorrecte indiquant que b n'est pas assignée. Dans Visual C# 2008, le même code est compilé correctement sans erreur.

        static void Main()
        {
            int? a, b;
            a = null;
            Console.WriteLine((b = null) ?? 17);
// No error in Visual C# 2008:Console.WriteLine(a + b);  

}

19

try-finally dans les itérateurs

Le bloc finally est maintenant exécuté lorsqu'un itérateur dans le bloc try s'échappe avec continue ou goto.

Dans Visual C# 2005, dans une construction try-finally, lorsque le contrôle passe hors d'un bloc itérateur dans le bloc try à l'aide d'une instruction goto ou continue, le bloc finally n'est pas exécuté. Dans Visual C# 2008, le bloc finally est exécuté dans ces cas-là.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DisposeTest
{
    class A : IDisposable
    {
        int m_n;
        internal A(int n)
        {
            m_n = n;
        }
        internal void Nothing() { }
        ~A()
        {
            Console.WriteLine("failed to dispose {0}", m_n);
        }
        #region IDisposable Members
        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Console.WriteLine("dispose {0}", m_n);
        }
        #endregion
    }
    class Program
    {
        static IEnumerable<A> B()
        {
            for (int nCount = 0; nCount < 2; nCount++)
            {
                Console.WriteLine("loop start");
                using (A A = new A(nCount))
                {
                    Console.WriteLine("using start");
                    // Section 1.
                    // Dispose not called correctly in Visual C# 2005.
                    if ((nCount % 2) == 0)
                        continue;
                    // Section 2.
                    // Dispose not called correctly in Visual C# 2005.
                    yield return A;
                    Console.WriteLine("using end");
                }
                Console.WriteLine("loop end");
            }
            yield break;
        }
        static void Main(string[] args)
        {
            foreach (A A in B())
            {
                A.Nothing();
            }
            Console.ReadLine();
        }
    }

}

20

Classes de base et interfaces

La construction de classe ignore maintenant les implémentations explicites des mêmes membres d'interface dans les classes de base.

Dans Visual C# 2005, lorsqu'une classe ne fournit pas d'implémentation pour un membre d'interface, le compilateur substitue les implémentations de classe de base même si elles sont déclarées comme implémentations d'interfaces explicites. Ce comportement n'est pas conforme à la spécification ECMA (European Computer Manufacturers Association). Visual C# 2008 implémente la spécification correctement. Dans l'exemple suivant, Visual C# 2005 imprime « B.Test ». Visual C# 2008 imprime « A.Test » correctement et ignore la méthode Test dans la classe B car il s'agit d'une implémentation d'interface explicite.

using System;
interface ITest
{
    string Test { get; }
    string Test2 { get; }
}
class A : ITest
{
    public string Test { get { return "A.Test"; } }
    public string Test2 { get { return "A.Test2"; } }
}
class B : A, ITest
{
    string ITest.Test { get { return "B.Test"; } }
    string ITest.Test2 { get { return "B.Test2"; } }
}
class C : B, ITest
{
    string ITest.Test2 { get { return "C.Test2"; } }
}
class Program
{
    static void Main()
    {
        C c = new C();
        Console.WriteLine(c.Test); 
// Visual C# 2008: "A.Test"
    }

}

21

Attributs

L'utilisation d'un membre obsolète génère désormais un avertissement de compilation.

Vous pouvez marquer des méthodes avec l'attribut Obsolete de façon à générer des erreurs ou des avertissements au moment de la compilation si les méthodes sont appelées. Lorsque vous placez cet attribut sur des méthodes virtuelles, il doit être placé sur la méthode de base. Si l'attribut Obsolete est placé sur une méthode override, il ne provoque pas d'erreur de compilation ou d'avertissement lors de l'appel. Dans Visual C# 2005, le compilateur vous autorisait à placer l'attribut Obsolete sur une méthode override, bien qu'il n'ait aucun effet dans ce cas. Dans Visual C# 2008, l'avertissement du compilateur Avertissement du compilateur (niveau 1) CS0809 est généré, « Le membre obsolète 'A.Filename' se substitue au membre non-obsolète 'Error.Filename' ». L'exemple suivant génère cet avertissement.

class A : Error
{
    [System.ObsoleteAttribute("Obsolete", true)]
    public override string Filename
    {
        set
        {
        }
    }
    public static void Main() { }
}
public class Error
{
    public virtual string Filename
    {
        set
        {
        }
        get
        {
            return "aa";
        }
    }
}
class B
{
    void TT()
    {
        new A().Filename = "Filename";
    }
}

22

Erreurs de génération

L'utilisation de l'option du compilateur /pdb sans /debug génère désormais une erreur.

Dans Visual C# 2005, aucun avertissement ou erreur n'est affiché lorsque vous spécifiez l'option /pdb mais pas l'option /debug. Visual C# crée simplement une version Release sans générer de fichier .pdb. Dans la version Release d'origine de Visual C# 2008, si vous spécifiez /pdb sans spécifier également /debug, le compilateur affiche une Erreur du compilateur CS2036.

23

Erreurs de type

Une erreur est désormais générée lorsqu'une condition switch est void.

Dans Visual C# 2005, aucune erreur n'est générée lorsqu'un appel de méthode void est utilisé dans une instruction switch. Dans Visual C# 2008, une Erreur du compilateur CS0151 est générée.

class C
{
    static void Main()
    {
// Produces CS0151:
        switch (M()) 
        {
            default:
                break;
        }
    }
    static void M()
    {
    }

}

24

Vérification de dépassement de capacité

Les conversions de décimale constante en intégral génèrent désormais une erreur de compilation différente.

Dans Visual C# 2005, le code suivant génère une Erreur du compilateur CS0133 : « L'expression assignée à 'b' doit être constante ».

const byte b = unchecked((byte)256M);

Dans Visual C# 2008, une Erreur du compilateur CS0031 est générée : « La valeur de constante '256M' ne peut pas être convertie en 'byte' ». Notez que l'erreur est générée même si le modificateur unchecked est appliqué.

25

Expressions constantes

La spécification est respectée plus étroitement concernant les expressions constantes.

Dans Visual C# 2008, plusieurs problèmes ont été corrigés selon lesquels Visual C# 2005 autorisait de manière incorrecte des opérateurs et des variables dans les expressions constantes. Dans Visual C# 2005, le code suivant est compilé sans erreur. Dans Visual C# 2008, une Erreur du compilateur CS0165, un Avertissement du compilateur (niveau 1) CS0184 et un Avertissement du compilateur (niveau 3) CS1718 sont générés :

class Program
{
    public static int Main()
    {
        int i1, i2, i3, i4, i5;
        // 'as' is not permitted in a constant expression.
        if (null as object == null)
            i1 = 1;
        // 'is' is not permitted in a constant expression.
        if (!(null is object))
            i2 = 1;
        // A variable is not permitted in a constant expression.
        int j3 = 0;
        if ((0 == j3 * 0) && (0 == 0 * j3))
            i3 = 1;
        int j4 = 0;
        if ((0 == (j4 & 0)) && (0 == (0 & j4)))
            i4 = 1;
        int? j5 = 1;
// Warning CS1718: Comparison made to same variable:
        if (j5 == j5) 
 
            i5 = 1;
        System.Console.WriteLine("{0}{1}{2}{3}{4}{5}", i1, i2, i3, i4, i5);
        return 1;
    }
}

26

Erreurs de type

Une erreur est désormais générée lorsqu'un type statique est utilisé comme paramètre dans un délégué ou dans une expression lambda.

Dans Visual C# 2005, aucune erreur n'est générée si un type statique est utilisé comme paramètre d'un délégué ou d'une méthode anonyme. Les types statiques ne peuvent pas être utilisés comme types de paramètres de méthode car ils ne peuvent pas être instanciés. La version Visual C# 2005 du compilateur autorise les types statiques comme types de paramètres dans les délégués et déclarations de méthodes anonymes. Si vous passez la valeur Null comme paramètre, ces délégués peuvent être appelés. Dans Visual C# 2008, une Erreur du compilateur CS0721 est générée si un type statique est utilisé comme paramètre d'un délégué ou d'une méthode anonyme, comme illustré dans l'exemple suivant.

public static class Test { }
public class Gen<T> { }
// Produces CS0721:
delegate int D(Test f); 
public class TestB
{
    public static void Main()
    {
        D d = delegate(Test f) { return 1; };
    }

}

27

Types nullables et expressions ??

Aucun avertissement n'est généré lorsque vous effectuez un cast d'une constante en un type nullable avant de l'assigner à un nullable (d'un type plus large).

Dans Visual C# 2005, le code suivant génère un Avertissement du compilateur (niveau 3) CS0219. Dans Visual C# 2008, aucun avertissement n'est généré.

ushort? usq2 = (byte?)0;

28

Résolution de surcharge

Une erreur est maintenant générée lorsqu'une résolution de surcharge ambiguë se produit sur des méthodes anonymes.

Les appels de méthode sur des méthodes surchargées doivent être résolus par le compilateur afin de déterminer la surcharge spécifique à appeler. Lorsque le type de paramètre d'un appel est déduit partiellement, la surcharge spécifique à appeler peut devenir ambiguë. Cela provoque une erreur de compilation.

Lorsqu'une méthode anonyme est passée comme paramètre de délégué, le type délégué de la méthode anonyme est déduit partiellement. Cela peut provoquer une ambiguïté lorsque le compilateur sélectionne la surcharge correcte.

Dans Visual C# 2005, le compilateur ne génère pas toujours d'erreur lorsqu'il n'existe aucune meilleure surcharge unique pour une méthode anonyme. Dans Visual C# 2008, une Erreur du compilateur CS0121 est générée, comme le montre l'exemple suivant.

class Program
{
    static int ol_invoked = 0;
    delegate int D1(int x);
    delegate T D1<T>(T x);
    delegate T D1<T, U>(U u);
    static void F(D1 d1) { ol_invoked = 1; }
    static void F<T>(D1<T> d1t) { ol_invoked = 2; }
    static void F<T, U>(D1<T, U> d1t) { ol_invoked = 3; }
    static int Test001()
    {
// Produces CS0121:
        F(delegate(int x) { return 1; });         if (ol_invoked == 1)
            return 0;
        else
            return 1;
    }
    static int Main()
    {
        return Test001();
    }
}

29

Erreurs de type

Une erreur est maintenant générée si vous déclarez un tableau de pointeurs vers des types managés.

Les pointeurs non sécurisés vers des types référence ne sont pas autorisés et provoquent des erreurs de compilation. Dans Visual C# 2005, il est possible de déclarer un tableau de pointeurs vers des types managés. Dans Visual C# 2008, une Erreur du compilateur CS0208 est générée : « Impossible de prendre l'adresse, d'obtenir la taille ou de déclarer un pointeur vers un type managé ('T') ».

unsafe class TestClass<T>
{
// Produces CS0208:
    static T*[] x = { }; 
// Produces CS0208:
    static void Test(T*[] arr) 
    {
    }
// Produces CS0208:
    static T*[] TestB() 
    {
        return x;
    }

}

30

Résolution de surcharge

Un avertissement est maintenant généré lorsque des méthodes candidates de résolution de surcharge varient uniquement par ref ou out.

Dans Visual C# 2005, lorsque le compilateur C# effectue la résolution de surcharge sur des types génériques, il ne vérifie pas si les arguments de type feront en sorte que les méthodes candidates varient uniquement par ref ou out. En conséquence, le choix des méthodes est laissé au Common Language Runtime (CLR) au moment de l'exécution et il sélectionne simplement la première méthode dans la liste. Dans Visual C# 2008, un Avertissement du compilateur (niveau 1) CS1956 est généré lorsque le compilateur détecte que deux méthodes candidates pour la résolution de surcharge varieront uniquement par ref ou out. Cette condition est illustrée dans l'exemple de code suivant.

using System;
class Base<T, S>
{
// Produces CS1956:
    public virtual void Test(out T x) 
    {
        Console.WriteLine("Test(out T x)");
        x = default(T);
    }
    public virtual void Test(ref S x)
    {
        Console.WriteLine("Test(ref T x)");
    }
}
interface IFace
{
    void Test(out int x);
}
class Derived : Base<int, int>, IFace
{
    static void Main()
    {
        IFace x = new Derived();
        int y;
        x.Test(out y);
    }

}

31

Types nullables et expressions ??

Une expression de fusion Null avec Null sur le côté gauche n'est plus évaluée en tant que constante Null.

Dans Visual C# 2005, une expression de fusion Null avec Null sur le côté gauche est évaluée en tant que constante Null. Dans Visual C# 2008, ce n'est plus le cas. Dans certains cas, le comportement de Visual C# 2005 permet de traiter de manière incorrecte des variables comme assignées de façon définie. Le code suivant est compilé et s'exécute sans erreur dans Visual C# 2005, mais dans Visual C# 2008 une Erreur du compilateur CS0165 est générée : « Utilisation d'une variable locale non assignée 'x' ».

static void Main()
    {
        int x;
        if (null == (decimal?)(null ?? null)) x = 1;
        // Producers CS0165 in Visual C# 2008:
        System.Console.WriteLine(x);    
    }

Voir aussi

Autres ressources

Mise en route de Visual C#

Historique des modifications

Date

Historique

Raison

Juillet 2008

Ajout d'une rubrique.

Modifications de fonctionnalités dans le SP1.