Ultime modifiche in Visual C# 2008

Aggiornamento: Luglio 2008

Ultime modifiche in Visual C# 2008 Service Pack 1

Nella tabella seguente sono elencate tutte le ultime modifiche in Visual C# 2008 Service Pack 1 che potrebbero avere un impatto su un'applicazione creata nella versione finale originale di Visual C# 2008 o di Visual C# 2005.

Numero di modifica

Category

Problema

Descrizione

1

Risoluzione dell'overload

L'inferenza dei tipi è ora inclusa nelle matrici dei tipi di puntatore nella risoluzione dell'overload dei metodi.

In Visual C# 2008 e nelle versioni precedenti, l'inferenza dei tipi fa in modo che le matrici dei tipi di puntatore vengano escluse dal processo di risoluzione dell'overload del metodo. Nel codice seguente, il compilatore di Visual C# 2005 seleziona la versione non generica di Test perché la versione generica di Test non viene considerata a causa del parametro di tipo int*[]. In Visual C# 2008, viene selezionata la versione generica di Test.

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

Indicizzatori

Il compilatore genera ora l'errore CS0466 per gli indicizzatori e le proprietà oltre che per i metodi.

Nella versione finale originale di Visual C# 2008 e nelle versioni precedenti, è possibile definire un'implementazione esplicita di un indicizzatore nella quale l'implementazione dispone del parametro params ma la definizione dell'interfaccia no. Questa costruzione è contraria alla specifica. In Visual C# 2008 SP1, questa costruzione genera l'Errore del compilatore CS0466, come mostrato nel codice seguente.

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

}

3

Tipi nullable e espressioni ??

A questo punto il compilatore valuta correttamente le espressioni nelle quali le variabili nullable vengono paragonate a se stesse.

Nella versione finale originale di Visual C# 2008, il codice seguente compila e restituisce "false" in fase di esecuzione. In Visual C# 2008 Service Pack 1, viene generato Avviso del compilatore (livello 3) CS1718 e restituito "true".

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

4

try-finally negli iteratori

L'esecuzione dei blocchi finally nidificati dagli iteratori che dispongono di istruzioni break è stata modificata.

Nella versione finale originale di Visual C# 2008, il codice seguente esegue il blocco finally esterno due volte. In Visual C# 2008 SP1, il finally esterno viene eseguito una volta.

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

Strutture ad albero dell'espressione

Il boxing errato delle espressioni dei metodi nelle strutture ad albero delle espressioni non si verifica più.

Nella versione finale originale di Visual C# 2008, il codice seguente restituisce 7, 0. La riga Console.WriteLine(e.Compile()(default(T))); restituisce zero perché il boxing di S non è stato eseguito correttamente. In Visual C# 2008 SP1, non si verifica alcun boxing e il programma restituisce 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

Inizializzatori di oggetti

L'inizializzazione dei tipi di valore negli inizializzatori di oggetti è stata corretta.

Nella versione finale originale di Visual C# 2008, la variabile locale b dell'esempio seguente non è stata inizializzata correttamente e il membro X dispone di un valore uguale a zero. In Visual C# 2008 SP1, S.X viene inizializzato correttamente in base a 1 in entrambe le espressioninew.

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

Conversioni di tipi

I valori letterali null non sono più convertibili in valori enum.

Nella versione finale originale di Visual C# 2008, i valori letterali null in alcuni casi possono essere convertiti in valori enum. In Visual C# 2008 SP1, Errore del compilatore CS1502 e Errore del compilatore CS1503 vengono prodotti se si tenta di eseguire questa operazione, come mostrato nell'esempio seguente.

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

Strutture ad albero dell'espressione

La struttura ad albero dell'espressione non valida genera ora l'eccezione corretta.

Nella versione finale originale di Visual C# 2008, una struttura ad albero dell'espressione contenente una chiamata a un metodo che non si trova nel tipo specificato genera un'eccezione System.Security.VerificationException. In Visual C# 2008 SP1, viene generato un System.ArgumentException, come mostrato nel codice seguente.

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

Attributi

CharSet.Unicode viene ora propagato nei tipi di supporto generati da C# per i campi di matrice fissi.

Il compilatore C# genera i tipi di supporto per incapsulare le matrici fisse. Nella versione finale originale di Visual C# 2008 e nelle versioni precedenti, il layout della matrice è sempre ANSI, anche se l'attributo StructLayout specifica CharSet.Unicode. Non è stato possibile modificarlo in codice sorgente C#. In Visual C# 2008 SP1, a prescindere dal valore CharSet specificato nell'attributo StructLayout viene utilizzato per costruire la classe di supporto, come mostrato nel codice seguente.

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

Controllo dell'overflow

stackalloc esegue ora un controllo dell'overflow.

Nella versione finale originale di Visual C# 2008, è possibile che un'allocazione stackalloc non riesca senza provocare un'eccezione. Ciò si verifica a causa di un'istruzione mul non controllata nel linguaggio MSIL (Microsoft Intermediate Language) generato quando la lunghezza della matrice viene moltiplicata per la dimensione di ogni elemento. In Visual C# 2008 SP1, viene generata un'istruzione mul.ovf anziché mul, pertanto gli overflow producono un System.OverflowEx ception quando l'allocazione viene tentata in fase di esecuzione.

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

Operatori di query standard

Le query sugli insiemi non generici utilizzano la semantica dei cast standard C#.

In espressioni di query LINQ su insiemi non generici ad esempio System.Collections.ArrayList, la clausola from della query viene riscritta dal compilatore per includere una chiamata all'operatore Cast<T>. Cast<T> converte tutti i tipi di elementi nel tipo specificato nella clausola from della query. Inoltre, nella versione finale originale di Visual C# 2008, l'operatore Cast<T> esegue anche alcune conversioni dei tipi di valore e conversioni definite dall'utente. Tuttavia, queste conversioni sono eseguite tramite la classe System.Convert anziché con la semantica C# standard. In alcuni scenari queste conversioni provocano anche notevoli problemi di prestazioni. In Visual C# 2008 SP1, l'operatore Cast<T> viene modificato per generare un InvalidCastException per il tipo di valore numerico e le conversioni definite dall'utente. Questa modifica elimina sia la semantica dei cast C# non standard che i problemi di prestazioni. Tale modifica viene illustrata nell'esempio seguente.

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

Ultime modifiche nella versione finale originale di Visual C# 2008

Nella tabella seguente vengono elencate tutte le ultime modifiche presenti nella versione finale originale di Visual C# 2008 che potrebbero impedire la compilazione di un'applicazione creata in Visual C# 2005 o che potrebbero modificarne il comportamento in fase di esecuzione.

Numero di modifica

Category

Problema

Descrizione

12

Conversioni di tipi

La conversione in enum di qualsiasi espressione costante con un valore pari a zero è ora consentita.

Il valore letterale 0 è convertibile in modo implicito in qualsiasi tipo enum. In Visual C# 2005 e nelle versioni precedenti del compilatore, ci sono anche alcune espressioni costanti che hanno un valore pari a 0 che possono essere convertite in modo implicito in qualsiasi tipo enum, ma la regola che determina quali di queste espressioni sono convertibili è poco chiara. In Visual C# 2008, tutte le espressioni costanti che sono uguali a 0 possono essere convertite in modo implicito in qualsiasi tipo enum.

Ciò potrebbe determinare alcune modifiche nel comportamento del codice esistente, ad esempio la risoluzione dell'overload del metodo che si basa sull'assenza di questa conversione implicita. Il codice seguente viene compilato correttamente in Visual C# 2005 e nelle versioni precedenti del compilatore, risolvendo la chiamata al metodo sul valore breve solo nell'overload int. In Visual C# 2008, questa chiamata è ambigua perché il valore breve è anche convertibile in modo implicito in E. In Visual C# 2008, il comportamento viene modificato per consentire la conversione di qualsiasi espressione costante che restituisce zero.

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

Attributi

L'errore si verifica quando lo stesso attributo TypeForwardedTo è presente due volte in un assembly.

In Visual C# 2005, se un assembly contiene due attributi System.Runtime.CompilerServices.TypeForwardedTo destinati allo stesso tipo non viene generato alcun errore. In Visual C# 2008, viene generato l'Errore del compilatore CS0739, come illustrato nell'esempio seguente.

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

Errori relativi ai tipi

È stato aggiunto un nuovo avviso sull'utilizzo di un membro del tipo di riferimento in una struttura.

Le regole di assegnazione definita per le strutture richiedono che la struttura sia impostata su un'istanza esistente del tipo o che ognuno dei membri sia assegnato prima che vi si faccia riferimento. In Visual C# 2005, quando viene utilizzato un membro del tipo di riferimento non assegnato di una struttura non viene generato alcun avviso o errore. In Visual C# 2008, viene generato l'Avviso del compilatore (livello 1) CS1060, come illustrato nell'esempio seguente.

    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

Controllo dell'overflow

Il controllo degli intervalli sui tipi decimali const è stato corretto.

In Visual C# 2005, quando si esegue il cast dei tipi decimali const, il controllo degli intervalli non è sempre corretto e potrebbe generare degli errori del compilatore errati. In Visual C# 2008, il codice seguente genera l'errore corretto: Errore del compilatore CS0031.

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

16

Controllo dell'overflow

Le conversioni in long non comprese nell'intervallo generano ora l'errore del compilatore corretto.

In Visual C# 2005, il codice seguente non genera un errore del compilatore. In Visual C# 2008, genera Errore del compilatore CS0031.

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

17

Buffer di dimensione fissa

L'accesso a un buffer a dimensione fissa in una struttura unsafe prima dell'assegnazione di un valore al buffer genera ora un errore del compilatore.

Le regole di assegnazione definita per i puntatori unsafe richiedono che il puntatore venga impostato prima di risolvere il riferimento ad esso. In Visual C# 2005, quando una struttura unsafe contiene un puntatore a una matrice, l'accesso al puntatore prima che gli venga assegnato un valore non genera un errore del compilatore. In Visual C# 2008, ciò genera: Errore del compilatore CS0165 come mostrato nel seguente codice.

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

18

Gli effetti collaterali sono ora mantenuti nelle espressioni null coalescing.

L'assegnazione definita e l'operatore ??.

In Visual C# 2005, in alcuni scenari gli effetti collaterali sul lato sinistro di un'espressione null coalescing non sono mantenuti. In questi casi, la seconda istruzione Console.WriteLine nell'esempio seguente genera un errore del compilatore errato che indica che b non è assegnato. In Visual C# 2008, lo stesso codice viene compilato correttamente senza errori.

        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 negli iteratori

Il blocco finally viene eseguito quando un iteratore nel blocco try utilizza caratteri di escape con continue o goto.

In Visual C# 2005, in una costruzione try-finally quando il controllo esce dal blocco iteratore nel blocco try tramite un'istruzione goto o continue, il blocco finally non viene eseguito. In Visual C# 2008, il blocco finally viene eseguito in questi casi.

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

Interfacce e classi base

La costruzione della classe ignora ora le implementazioni esplicite degli stessi membri dell'interfaccia nelle classi base.

In Visual C# 2005, quando una classe non fornisce un'implementazione per un membro dell'interfaccia, il compilatore sostituisce le implementazioni della classe base anche se vengono dichiarate come implementazioni esplicite dell'interfaccia. Questo comportamento non è conforme alla specifica di ECMA (European Computer Manufacturers Association). Visual C# 2008 implementa correttamente la specifica. Nell'esempio seguente, Visual C# 2005 stampa "B.Test". Visual C# 2008 stampa correttamente "A.Test" e ignora il metodo Test nella classe B perché è un'implementazione esplicita dell'interfaccia.

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

Attributi

L'utilizzo di un membro obsoleto genera ora un avviso del compilatore.

È possibile contrassegnare i metodi con l'attributo Obsolete per generare errori o avvisi in fase di compilazione se vengono richiamati i metodi. Quando si inserisce questo attributo sui metodi virtuali, l'attributo deve essere inserito sul metodo di base. Se l'attributo Obsolete viene inserito in un metodo di override, non genererà errori del compilatore o avvisi al momento della chiamata. In Visual C# 2005, il compilatore consente di inserire l'attributo Obsolete in un metodo di override, anche se l'attributo non ha alcun effetto se inserito. In Visual C# 2008, viene generato un avviso del compilatore Avviso del compilatore (livello 1) CS0809. Il membro obsoleto 'A.Filename' esegue l'override del membro non obsoleto 'Error.Filename'". Nell'esempio seguente viene generato questo avviso.

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

Errori durante la compilazione

L'utilizzo dell'opzione del compilatore /pdb senza /debug genera ora un errore.

In Visual C# 2005, non viene visualizzato alcun avviso o errore quando viene specificata l'opzione /pdb ma non l'opzione /debug. Visual C# crea solo una build di rilascio senza generare il file pdb. Nella versione finale originale di Visual C# 2008, se si specifica /pdb senza specificare anche /debug, il compilatore visualizza Errore del compilatore CS2036.

23

Errori relativi ai tipi

Un errore viene ora generato quando una condizione switch è void.

In Visual C# 2005, non viene generato alcun errore quando una chiamata al metodo void viene utilizzata in un'istruzione switch. In Visual C# 2008, viene generato un Errore del compilatore CS0151.

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

}

24

Controllo dell'overflow

Le conversioni da costante decimale a integrale generano ora un errore del compilatore diverso.

In Visual C# 2005, il codice seguente genererebbeErrore del compilatore CS0133: "L'espressione assegnata a 'b' deve essere costante".

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

In Visual C# 2008, viene generatoErrore del compilatore CS0031: il "valore costante '256M' non può essere convertito in un 'byte'." Notare che l'errore viene generato anche se viene applicato il modificatore unchecked.

25

Espressioni costanti

Esiste una maggiore conformità con la specifica per quanto riguarda le espressioni costanti.

In Visual C# 2008, sono stati corretti diversi problemi in cui Visual C# 2005 avrebbe erroneamente consentito operatori e variabili nelle espressioni costanti. In Visual C# 2005, il codice seguente viene compilato senza errori. In Visual C# 2008, vengono generati Errore del compilatore CS0165 , Avviso del compilatore (livello 1) CS0184 e Avviso del compilatore (livello 3) CS1718:

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

Errori relativi ai tipi

Un errore viene ora generato quando un tipo statico viene utilizzato come parametro in un delegato o in un'espressione lambda.

In Visual C# 2005, se un tipo statico viene utilizzato come parametro per un delegato o un metodo anonimo non viene generato alcun errore. I tipi statici non possono essere utilizzati come tipi di parametri del metodo perché non è possibile creare una loro istanza. La versione Visual C# 2005 del compilatore consente l'uso di tipi statici come tipi di parametro all'interno delle dichiarazioni di delegati e di metodi anonimi. Se si passa null come parametro, è possibile richiamare tali delegati. In Visual C# 2008, viene generato l'errore Errore del compilatore CS0721 se un tipo statico viene utilizzato come parametro per un delegato o un metodo anonimo, come mostrato nell'esempio seguente.

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

Tipi nullable e espressioni ??

Quando si esegue il cast di una costante a un tipo nullable prima di assegnarla a un valore nullable (di tipo più ampio) non viene generato alcun avviso.

In Visual C# 2005, il codice seguente genererebbe Avviso del compilatore (livello 3) CS0219. In Visual C# 2008, non viene generato alcun avviso.

ushort? usq2 = (byte?)0;

28

Risoluzione dell'overload

Un errore viene ora generato quando si verifica una risoluzione ambigua dell'overload sui metodi anonimi.

Le chiamate al metodo sui metodi di overload devono essere risolte dal compilatore per determinare quale overload specifico richiamare. Quando il tipo di parametro di una chiamata viene dedotto parzialmente, l'overload specifico da richiamare può diventare ambiguo. Questa situazione genera errori di compilazione.

Nel caso di un metodo anonimo passato come parametro del delegato, il tipo di delegato del metodo anonimo viene dedotto parzialmente. Ciò può causare ambiguità quando il compilatore deve selezionare l'overload corretto.

In Visual C# 2005, il compilatore non genera sempre un errore quando non esiste alcun overload migliore per un metodo anonimo. In Visual C# 2008, viene generato l'Errore del compilatore CS0121, come illustrato nell'esempio seguente.

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

Errori relativi ai tipi

Un errore viene ora generato se si dichiara una matrice di puntatori ai tipi gestiti.

I puntatori unsafe ai tipi di riferimento non sono consentiti e provocano errori del compilatore. In Visual C# 2005, è possibile dichiarare una matrice di puntatori ai tipi gestiti. In Visual C# 2008, viene generatoErrore del compilatore CS0208 : "Impossibile accettare l'indirizzo di un tipo gestito ('tipo'), recuperarne la dimensione o dichiarare un puntatore a esso.

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

}

30

Risoluzione dell'overload

Un avviso viene ora generato quando i metodi candidati della risoluzione dell'overload variano solo in base a ref o out.

In Visual C# 2005, quando il compilatore C# esegue la risoluzione dell'overload sui tipi generici, non verifica se gli argomenti di tipo faranno in modo che i metodi candidati varino solo in base a ref o out. Di conseguenza, la scelta dei metodi viene lasciata al Common Language Runtime (CLR) in fase di esecuzione e si limita a selezionare il primo metodo dell'elenco. In Visual C# 2008, Avviso del compilatore (livello 1) CS1956 viene generato quando il compilatore rileva che due metodi candidati per la risoluzione dell'overload varieranno solo in base a ref o out. Tale condizione viene illustrata nell'esempio seguente.

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

Tipi nullable e espressioni ??

Un'espressione null-coalescing contenente un valore null sul lato sinistro non viene più considerata come costante null.

In Visual C# 2005, un'espressione null-coalescing contenente un valore null sul lato sinistro non viene più considerata come costante null. In Visual C# 2008, ciò non si verifica più. In alcuni casi, il comportamento diVisual C# 2005 consente alle variabili di essere erroneamente considerate come definitivamente assegnate. Il seguente codice viene compilato ed eseguito senza errori in Visual C# 2005, ma in Visual C# 2008 viene generato Errore del compilatore CS0165: "Utilizzo di variabile locale 'x' non assegnata".

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

Vedere anche

Altre risorse

Guida introduttiva a Visual C#

Cronologia delle modifiche

Date

History

Motivo

Luglio 2008

Argomento aggiunto.

Modifica di funzionalità in SP1.