77

What member should I implement in my arbitrary structure to make the following assignment possible:

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");

How should this be done?

Veverke
  • 9,208
  • 4
  • 51
  • 95
Yippie-Ki-Yay
  • 22,026
  • 26
  • 90
  • 148

4 Answers4

122

You use an implicit operator that converts the string value to a struct value:

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

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

}

Example:

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

Output:

Lol
3
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • the problem I can see here is a desvirtualization of struct... when you use the 'new' operator to return the struct, this operator will put the data in the heap... so maybe its better to use this code as a static class (so there is a code desambiguation for the programmmer)... and things gain coherence... – ZEE Nov 08 '17 at 03:36
  • 5
    @ZEE: The `new` operator doesn't case a heap allocation for a struct. There isn't actually any parameterless constructor to call, it's just C# syntax for creating a struct value. – Guffa Nov 10 '17 at 14:55
10

Structure types should, whenever practical, either have all of their state encapsulated in public fields which may independently be set to any values which are valid for their respective type, or else behave as a single unified value which can only bet set via constructor, factory, method, or else by passing an instance of the struct as an explicit ref parameter to one of its public methods. Contrary to what some people claim, that there's nothing wrong with a struct having public fields, if it is supposed to represent a set of values which may sensibly be either manipulated individually or passed around as a group (e.g. the coordinates of a point). Historically, there have been problems with structures that had public property setters, and a desire to avoid public fields (implying that setters should be used instead) has led some people to suggest that mutable structures should be avoided altogether, but fields do not have the problems that properties had. Indeed, an exposed-field struct is the ideal representation for a loose collection of independent variables, since it is just a loose collection of variables.

In your particular example, however, it appears that the two fields of your struct are probably not supposed to be independent. There are three ways your struct could sensibly be designed:

  • You could have the only public field be the string, and then have a read-only "helper" property called length which would report its length if the string is non-null, or return zero if the string is null.

  • You could have the struct not expose any public fields, property setters, or mutating methods, and have the contents of the only field--a private string--be specified in the object's constructor. As above, length would be a property that would report the length of the stored string.

  • You could have the struct not expose any public fields, property setters, or mutating methods, and have two private fields: one for the string and one for the length, both of which would be set in a constructor that takes a string, stores it, measures its length, and stores that. Determining the length of a string is sufficiently fast that it probably wouldn't be worthwhile to compute and cache it, but it might be useful to have a structure that combined a string and its GetHashCode value.

It's important to be aware of a detail with regard to the third design, however: if non-threadsafe code causes one instance of the structure to be read while another thread is writing to it, that may cause the accidental creation of a struct instance whose field values are inconsistent. The resulting behaviors may be a little different from those that occur when classes are used in non-threadsafe fashion. Any code having anything to do with security must be careful not to assume that structure fields will be in a consistent state, since malicious code--even in a "full trust" enviroment--can easily generate structs whose state is inconsistent if that's what it wants to do.

PS -- If you wish to allow your structure to be initialized using an assignment from a string, I would suggest using an implicit conversion operator and making Length be a read-only property that returns the length of the underlying string if non-null, or zero if the string is null.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 5
    Although you make some interesting points, this doesn't actually answer the question. – Edurne Pascual Jan 14 '14 at 09:18
  • 1
    I didn't notice the last assignment--just the first. To allow for the latter, you could define an implicit conversion operator from `String` to your structure type. If you do that, you may wish to have `Length` be a read-only property which simply reports the length of the assigned string field, or zero if that field is `null`. – supercat Jan 14 '14 at 15:57
  • You should include that in your answer. That'd turn it into an actual answer. And once you edit it I'll be able to withdraw my downvote. – Edurne Pascual Jan 31 '14 at 13:47
  • @supercat you are my hero. – layer07 Nov 19 '22 at 14:44
5
  1. Will "length" ever deviate from the real length of "s". If the answer is no, then you don't need to store length, because strings store their length already, and you can just call s.Length.

  2. To get the syntax you asked for, you can implement an "implicit" operator like so:

    static implicit operator MyStruct(string s) {
        return new MyStruct(...);
    }
    
  3. The implicit operator will work, regardless of whether you make your struct mutable or not.

Scott Wisniewski
  • 24,561
  • 8
  • 60
  • 89
1

Your struct can have methods and properties... why not try

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

Correction @Guffa's answer shows that it is possible... more info here: http://www.codeproject.com/KB/cs/Csharp_implicit_operator.aspx

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Adam Spicer
  • 2,703
  • 25
  • 37