Cela peut paraître stupide. Nous savons que nous pouvons attribuer une valeur à une variable de chaîne comme suit.
String name = "myname";

String est un type de référence, mais ne nécessite pas l'opérateur new lors de la déclaration et de l'affectation de valeur. Si je veux concevoir une classe personnalisée avec un tel comportement, comment procéder?

Merci

c#
3
Anu Viswan 27 juil. 2017 à 14:36

4 réponses

Vous pouvez y parvenir avec vos propres classes en utilisant des opérateurs de conversion implicites - en gros, vous définissez une méthode statique dans votre classe qui peut créer une instance à partir d'une valeur. Vérifie ça:

public class MyClass
{
   public static implicit operator MyClass (int val)
   {
       return new MyClass { Value = new String('!', val)};
   }
   public string Value {get;set;}
}

Cette classe contient une chaîne. Lors d'un casting implicite à partir d'un int, il initialisera la classe avec le nombre int de points d'exclamation:

MyClass obj = 5;
Console.WriteLine(obj.Value); // outputs !!!!!
1
Avner Shahar-Kashtan 27 juil. 2017 à 11:46

Vous ne pouvez pas concevoir un class avec un tel comportement. Mais vous pouvez concevoir un struct. Et vous n'avez rien à faire de spécial: un struct peut toujours être instancié simplement en le déclarant.

Comme pour string s = "literal", string est une classe, mais son instanciation à l'aide d'un littéral est gérée spécialement par le compilateur. C'est équivalent à string s = new string( literal ).

-1
Mike Nakis 27 juil. 2017 à 11:42

Cette fonctionnalité est appelée constantes littérales . Le compilateur ne les supporte que pour certains types, la plupart d'entre eux sont ce que nous appelons de manière informelle des types primitve . Ceux-ci sont:

  1. Littéraux booléens: true et false.

  2. Entiers littéraux: int, uint, long et ulong.

    Le type exact du littéral est le type spécifié via le suffixe du littéral ou déduit de la valeur du littéral (le type inféré sera toujours un type signé).

    Si le type inféré n'est pas le type déclaré de la variable, une conversion implicite est automatiquement effectuée si elle est disponible (sinon une erreur de compilation est générée).

  3. Littéraux réels: float, double et decimal

    Le type du littéral sera toujours double sauf indication contraire par le suffixe du littéral. Là encore, une conversion implicite vers le type de variables déclaré sera effectuée si nécessaire et disponible.

  4. Littéraux de caractères: 'a', '1', '\ u1000', etc.

  5. Littéraux de chaîne: deux types de chaînes littérales sont pris en charge: les littéraux de chaîne normaux et les littéraux de chaîne verbatim : "C:\\Path" et @"C:\Path".

  6. Le littéral null : null

Tous ceux-ci ont un support spécifique du compilateur. Vous ne pouvez en aucun cas implémenter votre propre type avec son type de comportement. Ce que vous pouvez faire est d’implémenter une conversion implicite de l’un des littéraux ci-dessus (à l’exception du littéral null ) en votre type et de l’imiter de façon littérale. constantes.

N'oubliez pas que vous ne imitez qu'avec du sucre visuel, car ce ne sont certainement pas des constantes littérales pas :

struct MyLiteralType
{
     public static implicit MyLiteralType(int i) => new MyLiteralType(i);
}

const MyLiteralType myLiteralTypeConstant = 1; //--> compile time error.
1
InBetween 27 juil. 2017 à 12:19

La "magie du compilateur" intégrée s'en occupe. Sous le capot, les littéraux pour les chaînes, les entiers, les longs, etc. sont convertis en opérations pour créer correctement l'objet ou la valeur correspondante au moment de l'exécution, sans que vous ayez à utiliser l'opérateur new.

String et Int32 sont des classes

Techniquement, Int32 est un struct, pas un class, mais la même logique s'applique.

1
dasblinkenlight 27 juil. 2017 à 11:39