Risposte:
Questo è un vincolo per il parametro generico T
. Deve essere un class
(tipo di riferimento) e deve avere un costruttore predefinito senza parametri pubblici.
Che i mezzi T
non possono essere int
, float
, double
, DateTime
o qualsiasi altro struct
(tipo di valore).
Potrebbe essere un string
qualsiasi tipo di riferimento personalizzato, purché abbia un costruttore predefinito o senza parametri.
new()
specifica con precisione "deve avere un costruttore pubblico senza parametri"
Questi sono vincoli di tipo generico. Nel tuo caso ce ne sono due:
where T : class
Significa che il tipo T
deve essere un tipo di riferimento (non un tipo di valore).
where T : new()
Significa che il tipo T
deve avere un costruttore senza parametri. Avere questo vincolo ti permetterà di fare qualcosa come T field = new T();
nel tuo codice che altrimenti non potresti fare.
Quindi combinare i due usando una virgola per ottenere:
where T : class, new()
dove T: struct
L'argomento type deve essere un tipo di valore. È possibile specificare qualsiasi tipo di valore tranne Nullable. Vedere Uso dei tipi nullable (Guida per programmatori C #) per ulteriori informazioni.
dove T: classe
L'argomento type deve essere un tipo di riferimento, incluso qualsiasi classe, interfaccia, delegato o tipo di array. (Vedi nota sotto.)
dove T: new () L'argomento type deve avere un costruttore pubblico senza parametri. Se utilizzato insieme ad altri vincoli, il nuovo vincolo () deve essere specificato per ultimo.
dove T: [nome classe base]
L'argomento tipo deve essere o derivare dalla classe base specificata.
dove T: [nome interfaccia]
L'argomento tipo deve essere o implementare l'interfaccia specificata. È possibile specificare più vincoli di interfaccia. L'interfaccia vincolante può anche essere generica.
dove T: U
L'argomento di tipo fornito per T deve essere o derivare dall'argomento fornito per U. Questo è chiamato un vincolo di tipo nudo.
class
e new
sono 2 vincoli sul parametro di tipo genericoT
.
Rispettivamente assicurano:
class
L'argomento type deve essere un tipo di riferimento; questo vale anche per qualsiasi classe, interfaccia, delegato o tipo di array.
new
L'argomento type deve avere un costruttore pubblico senza parametri. Se utilizzato insieme ad altri vincoli, il vincolo new () deve essere specificato per ultimo.
La loro combinazione significa che il tipo T
deve essere un Tipo di riferimento (non può essere un Tipo valore ) e deve avere un costruttore senza parametri.
Esempio:
struct MyStruct { } // structs are value types
class MyClass1 { } // no constructors defined, so the class implicitly has a parameterless one
class MyClass2 // parameterless constructor explicitly defined
{
public MyClass2() { }
}
class MyClass3 // only non-parameterless constructor defined
{
public MyClass3(object parameter) { }
}
class MyClass4 // both parameterless & non-parameterless constructors defined
{
public MyClass4() { }
public MyClass4(object parameter) { }
}
interface INewable<T>
where T : new()
{
}
interface INewableReference<T>
where T : class, new()
{
}
class Checks
{
INewable<int> cn1; // ALLOWED: has parameterless ctor
INewable<string> n2; // NOT ALLOWED: no parameterless ctor
INewable<MyStruct> n3; // ALLOWED: has parameterless ctor
INewable<MyClass1> n4; // ALLOWED: has parameterless ctor
INewable<MyClass2> n5; // ALLOWED: has parameterless ctor
INewable<MyClass3> n6; // NOT ALLOWED: no parameterless ctor
INewable<MyClass4> n7; // ALLOWED: has parameterless ctor
INewableReference<int> nr1; // NOT ALLOWED: not a reference type
INewableReference<string> nr2; // NOT ALLOWED: no parameterless ctor
INewableReference<MyStruct> nr3; // NOT ALLOWED: not a reference type
INewableReference<MyClass1> nr4; // ALLOWED: has parameterless ctor
INewableReference<MyClass2> nr5; // ALLOWED: has parameterless ctor
INewableReference<MyClass3> nr6; // NOT ALLOWED: no parameterless ctor
INewableReference<MyClass4> nr7; // ALLOWED: has parameterless ctor
}
new (): Specificare il vincolo new () significa che il tipo T deve usare un costruttore senza parametri, quindi un oggetto può essere istanziato da esso - vedi Costruttori predefiniti .
class: significa che T deve essere un tipo di riferimento, quindi non può essere int, float, double, DateTime o altra struttura (tipo di valore).
public void MakeCars()
{
//This won't compile as researchEngine doesn't have a public constructor and so can't be instantiated.
CarFactory<ResearchEngine> researchLine = new CarFactory<ResearchEngine>();
var researchEngine = researchLine.MakeEngine();
//Can instantiate new object of class with default public constructor
CarFactory<ProductionEngine> productionLine = new CarFactory<ProductionEngine>();
var productionEngine = productionLine.MakeEngine();
}
public class ProductionEngine { }
public class ResearchEngine
{
private ResearchEngine() { }
}
public class CarFactory<TEngine> where TEngine : class, new()
{
public TEngine MakeEngine()
{
return new TEngine();
}
}
Ciò significa che quel tipo T
deve essere una classe e avere un costruttore che non accetta alcun argomento.
Ad esempio, devi essere in grado di farlo:
T t = new T();
Il nuovo vincolo () consente al compilatore di sapere che qualsiasi argomento di tipo fornito deve avere un costruttore accessibile senza parametri - o predefinito -
Quindi dovrebbe essere, T
deve essere una classe e avere un costruttore accessibile senza parametri o predefinito.
Ciò che viene dopo "Where" è un vincolo sul tipo generico T che hai dichiarato, quindi:
class significa che la T dovrebbe essere una classe e non un tipo di valore o una struttura.
new () indica che la classe T dovrebbe avere un costruttore predefinito privo di parametri pubblici definito.
Si chiama 'vincolo' sul parametro generico T. Significa che T deve essere un tipo di riferimento (una classe) e che deve avere un costruttore predefinito pubblico.
Questo fa parte del meccanismo Generics, in cui la parola chiave where aggiunge vincoli ai tipi che devono essere implementati per poter essere utilizzati come parametri di tipo.