2010-12-12 73 views
40

Quel membre dois-je mettre en œuvre dans ma structure arbitraire de faire l'affectation suivante possible:Comment initialiser struct?

public struct MyStruct { 
    String s; 
    Int length; 
} 

MyStruct myStruct = new MyStruct { s = "Hello", length = 5 }; 

// Now, I want the following code to set the 's' to "Lol" and the 
// length to 3 (length of "Lol"). The second part should be done 
// automatically. 
myStruct = "Lol"; // Or myStruct = String("Lol"); 

Comment doit-il être fait?

+4

Veuillez ne pas créer de structures mutables. http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil – Ani

+0

'String's connaissent déjà leur longueur. Pourquoi auriez-vous besoin d'une structure comme celle-ci? –

+0

@Karl Knechtel: Je suppose que c'est un exemple pour montrer le principe. Le code montré ne compile même pas ... – Guffa

Répondre

72

Vous utilisez un opérateur implicite qui convertit la valeur de chaîne en une valeur de structure:

public struct MyStruct { 
    public string s; 
    public int length; 

    public static implicit operator MyStruct(string value) { 
    return new MyStruct() { s = value, length = value.Length }; 
    } 

} 

Exemple:

MyStruct myStruct = "Lol"; 
Console.WriteLine(myStruct.s); 
Console.WriteLine(myStruct.length); 

Sortie:

Lol 
3 
+0

le problème que je peux voir ici est une desvirtualisation de struct ... lorsque vous utilisez l'opérateur 'new' pour retourner la structure, cet opérateur mettra les données dans le tas ... alors peut-être vaut-il mieux utiliser ce code comme classe statique (il y a donc une désambiguïsation de code pour le programmemmer) ... et les choses gagnent en cohérence ... – ZEE

+0

@ZEE: L'opérateur 'new' ne présente pas une allocation de tas pour une structure. Il n'y a pas de constructeur sans paramètre à appeler, c'est juste une syntaxe C# pour créer une valeur de struct. – Guffa

0

Votre struct peut avoir des méthodes et des propriétés ... pourquoi ne pas essayer

public struct MyStruct { 
    public string s; 
    public int length { return s.Length; } 
} 

Correction @ La réponse de Guffa montre qu'il est possible ... Plus d'information ici: http://www.codeproject.com/KB/cs/Csharp_implicit_operator.aspx

+0

Oui, c'est possible. – Guffa

+0

@Guffa: réponse intéressante ... Je n'ai pas considéré l'opérateur implicite. –

4
  1. Est-ce que "longueur" écarter jamais de la longueur réelle de "s". Si la réponse est non, vous n'avez pas besoin de stocker la longueur, car les chaînes stockent déjà leur longueur et vous pouvez simplement appeler s.Length.

  2. Pour obtenir la syntaxe que vous avez demandé, vous pouvez mettre en œuvre un opérateur « implicite » comme ceci:

    static implicit operator MyStruct(string s) { 
        return new MyStruct(...); 
    } 
    
  3. L'opérateur implicite fonctionnera, que vous faites votre struct mutable ou non.

7

types de structure devraient, chaque fois que possible, soit ont tous leur état encapsulé dans des domaines publics qui peuvent être indépendamment mis à toutes les valeurs qui sont valides pour leur type respectif, ou bien se comportent comme une seule valeur unique qui peut uniquement bet défini via constructor, factory, method, ou bien en passant une instance de la structure en tant que paramètre explicite ref à l'une de ses méthodes publiques. Contrairement à ce que certains prétendent, il n'y a rien de mal dans une structure ayant des champs publics, si elle est censée représenter un ensemble de valeurs qui peuvent être soit manipulées individuellement soit transmises en groupe (par exemple les coordonnées d'un point). Historiquement, il y avait des problèmes avec les structures qui avaient des créateurs de propriétés publiques, et le désir d'éviter les champs publics (impliquant que les setters devraient être utilisés à la place) a conduit certaines personnes à suggérer que les structures mutables devraient être complètement évitées. problèmes que les propriétés avaient. En effet, une structure de champ exposé est la représentation idéale pour une collection de variables indépendantes, car est juste une collection de variables.

Dans votre exemple particulier, cependant, il semble que les deux champs de votre structure ne sont probablement pas supposés être indépendants. Il y a trois façons votre struct pourrait raisonnablement être conçue:

  • Vous pourriez avoir le seul champ public soit la chaîne, puis avoir une lecture seule « aide » propriété appelée length qui compte sa longueur si la chaîne est non nul, ou renvoie zéro si la chaîne est nulle.Vous pouvez faire en sorte que la structure n'expose pas de champs publics, de paramètres de propriété ou de méthodes de mutation, et que le contenu du champ unique - une chaîne privée - soit spécifié dans le constructeur de l'objet. Comme ci-dessus, length serait une propriété qui indiquerait la longueur de la chaîne stockée. Vous pouvez faire en sorte que la structure n'expose pas de champs publics, de paramètres de propriété ou de méthodes de mutation et possède deux champs privés: un pour la chaîne et un pour la longueur, tous deux définis dans un constructeur prenant une chaîne, le stocke, mesure sa longueur et stocke cela. La détermination de la longueur d'une chaîne est suffisamment rapide pour qu'il ne soit probablement pas utile de la calculer et de la mettre en cache, mais il peut être utile d'avoir une structure qui combine une chaîne et sa valeur GetHashCode.

Il est important d'être au courant d'un détail en ce qui concerne la troisième conception, cependant: si le code non threadsafe provoque une instance de la structure à lire, tandis qu'un autre thread est en train d'écrire à elle, qui peut provoquer la création accidentelle d'une instance de structure dont les valeurs de champs sont incohérentes. Les comportements qui en résultent peuvent être légèrement différents de ceux qui se produisent lorsque les classes sont utilisées de manière non threadsafe. Tout code ayant un rapport avec la sécurité doit faire attention à ne pas supposer que les champs de structure seront dans un état cohérent, car un code malveillant - même dans un environnement de confiance totale - peut facilement générer des structures dont l'état est incohérent. il veut faire.

PS - Si vous souhaitez autoriser votre structure à initialiser à l'aide d'une cession d'une chaîne, je suggère d'utiliser un opérateur de conversion implicite et en faisant Length une propriété en lecture seule qui retourne la longueur du sous-jacent chaîne si non nulle, ou zéro si la chaîne est nulle.

+1

Bien que vous fassiez quelques points intéressants, cela ne répond pas vraiment à la question. –

+0

Je n'ai pas remarqué la dernière affectation - juste la première. Pour permettre ce dernier, vous pouvez définir un opérateur de conversion implicite de 'String' à votre type de structure. Si vous faites cela, vous pouvez souhaiter que 'Length' soit une propriété en lecture seule qui indique simplement la longueur du champ de chaîne affecté, ou zéro si ce champ est' null'. – supercat

+0

Vous devriez inclure cela dans votre réponse. Cela en ferait une réponse réelle. Et une fois que vous l'éditerez, je serai en mesure de retirer mon downvote. –