Que signifie «où T: classe, nouveau ()»?

Réponses:

329

C'est une contrainte sur le paramètre générique T. Il doit être un class(type de référence) et doit avoir un constructeur par défaut public sans paramètre.

Cela veut dire Tne peut pas être un int, float, double, DateTimeou tout autre struct(type de valeur).

Il peut s'agir d'un stringou de tout autre type de référence personnalisé, tant qu'il possède un constructeur par défaut ou sans paramètre.

NerdFury
la source
5
Juste pour clarifier, si vous n'avez pas la clause de classe dans le cadre de où T ..., alors il est sûr d'utiliser int, float, double etc.
AboutDev
1
@AboutDev correct, vous n'avez pas à imposer de contraintes sur votre paramètre de type générique. Mais si vous créez un générique qui s'attend à ne fonctionner que sur les types de référence ou de valeur, vous devez le spécifier. Sans contrainte, vous pouvez vous attendre à des types de référence (classes) ou à des types de valeurs (structs (int, float, double ...)).
NerdFury
1
Et où T: [nom de l'interface], new ()? Avez-vous toujours besoin d'un constructeur sans paramètre?
Vince Tino
3
Pour clarifier le commentaire de Justin, un constructeur vide n'a pas d'instructions (comme le constructeur par défaut) tandis qu'un constructeur sans paramètre peut contenir des instructions (comme initialiser une liste).
DharmaTurtle
@VinceTino: new()précise précisément "doit avoir un constructeur public sans paramètre"
Flater
162

Ce sont des contraintes de type génériques. Dans votre cas, il y en a deux:

where T : class

Signifie que le type Tdoit être un type de référence (pas un type de valeur).

where T : new()

Signifie que le type Tdoit avoir un constructeur sans paramètre. Avoir cette contrainte vous permettra de faire quelque chose comme T field = new T();dans votre code que vous ne pourriez pas faire autrement.

Vous combinez ensuite les deux à l'aide d'une virgule pour obtenir:

where T : class, new()
Justin Niessner
la source
Bons points pour les deuxième et troisième, juste pour ajouter des informations, je pense que le deuxième point est utile lors d'une réflexion de type générique. par exemple. T t = nouveau T (); t.GetType (). GetProperty ("ID"). SetValue (t, uniqueId, null);
Jerry Liang
1
Je pense qu'il est redondant de dire où T: class, new (), car new () implique déjà la classe car les structures ne peuvent pas avoir de constructeurs par défaut.
DharmaTurtle
@DharmaTurtle, "les structures ne peuvent pas contenir de constructeurs explicites sans paramètres", ne signifie pas qu'elles n'en ont pas, cela signifie que vous ne pouvez pas en définir un. source: msdn.microsoft.com/tr-tr/library/aa288208(v=vs.71).aspx
rustem
121

où T: struct

L'argument type doit être un type valeur. Tout type de valeur, à l'exception de Nullable, peut être spécifié. Voir Utilisation de types Nullable (Guide de programmation C #) pour plus d'informations.

où T: classe

L'argument type doit être un type de référence, comprenant tout type de classe, d'interface, de délégué ou de tableau. (Voir note ci-dessous.)

où T: new () L'argument type doit avoir un constructeur public sans paramètre. Lorsqu'elle est utilisée conjointement avec d'autres contraintes, la nouvelle contrainte () doit être spécifiée en dernier.

où T: [nom de la classe de base]

L'argument type doit être ou dériver de la classe de base spécifiée.

où T: [nom de l'interface]

L'argument type doit être ou implémenter l'interface spécifiée. Plusieurs contraintes d'interface peuvent être spécifiées. L'interface contraignante peut également être générique.

où T: U

L'argument de type fourni pour T doit être ou dériver de l'argument fourni pour U. Cela s'appelle une contrainte de type nu.

Mohammed Jubayer
la source
23
C'était utile, mais un lien vers la source .
Skean
26

class& newsont 2 contraintes sur le paramètre de type génériqueT .
Respectivement, ils assurent:

class

L'argument type doit être un type de référence; cela s'applique également à tout type de classe, d'interface, de délégué ou de tableau.

new

L'argument type doit avoir un constructeur public sans paramètre. Lorsqu'elle est utilisée avec d'autres contraintes, la nouvelle contrainte () doit être spécifiée en dernier.

Leur combinaison signifie que le type Tdoit être un type de référence (ne peut pas être un type de valeur ) et doit avoir un constructeur sans paramètre.

Exemple:

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
}
Sergio
la source
1
Bonne démonstration. Merci.
Subhan Ali
15

new (): La spécification de la contrainte new () signifie que le type T doit utiliser un constructeur sans paramètre, afin qu'un objet puisse en être instancié - voir Constructeurs par défaut .

classe: signifie que T doit être un type de référence, il ne peut donc pas être un entier, flottant, double, DateTime ou autre struct (type de valeur).

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();
    }
}
Brendan
la source
6

Cela signifie que ce type Tdoit être une classe et avoir un constructeur qui ne prend aucun argument.

Par exemple, vous devez pouvoir faire ceci:

T t = new T();
Evan Mulawski
la source
1
pas seulement un constructeur, mais un constructeur qui ne prend aucun argument.
NerdFury
@NerdFury: Merci. C'est un élément important. Corrigée.
Evan Mulawski
5

où (référence C #)

La nouvelle contrainte () permet au compilateur de savoir que tout argument de type fourni doit avoir un constructeur accessible sans paramètre - ou par défaut -

Il devrait donc être, Tdoit être une classe et avoir un constructeur accessible sans paramètre - ou par défaut.

Fredrik Widerberg
la source
4

Ce qui vient après le "Où" est une contrainte sur le type générique T que vous avez déclaré, donc:

  • classe signifie que le T doit être une classe et non un type de valeur ou une structure.

  • new () indique que la classe T devrait avoir un constructeur par défaut public sans paramètre défini.

Otman IGHOULASSEN
la source
1

Cela s'appelle une «contrainte» sur le paramètre générique T. Cela signifie que T doit être un type de référence (une classe) et qu'il doit avoir un constructeur public par défaut.


la source
1

Cela fait partie du mécanisme Generics, où le mot-clé where ajoute des contraintes aux types à implémenter pour être utilisé comme paramètres de type.

Peter Lillevold
la source
0

lorsque vous utilisez la classe dans des contraintes, cela signifie que vous ne pouvez utiliser que le type de référence, une autre chose à ajouter est quand utiliser la contrainte new () , ce doit être la dernière chose que vous écrivez dans les termes de contraintes.

Rebwar
la source