Skip to main content
  • use a default value, such as "N.A.", for the Value property. Doing so, even when an instance of NonEmptyString is created via the default constructor the wrapped string is actually a non empty string
  • add a private readonly field isInitialized, whose default value is false, in order to track whether the right constructor has been called (the field is set to true only in the constructor overload having the string parameter). Doing so it is possible to add a check at the beginning of each type member, so that an InvalidOperationException is raised each time the programmer creates an instance via the default constructor and tries to use it in itshis code.

If NonEmptyStringNonEmptyString were be defined as a class it would be useless, because each piece of code receiving an instance of NonEmptyStringNonEmptyString would have to check whether the instance contains a null reference. Instead, I would like to get a type giving the guarantee that each possible instance contains an actual string (that is a string other than null, the empty string and a sequence of spaces).

  • use a default value, such as "N.A.", for the Value property. Doing so, even when an instance of NonEmptyString is created via the default constructor the wrapped string is actually a non empty string
  • add a private readonly field isInitialized, whose default value is false, in order to track whether the right constructor has been called (the field is set to true only in the constructor overload having the string parameter). Doing so it is possible to add a check at the beginning of each type member, so that an InvalidOperationException is raised each time the programmer creates an instance via the default constructor and tries to use it in its code

If NonEmptyString were be defined as a class it would be useless, because each piece of code receiving an instance of NonEmptyString would have to check whether the instance contains a null reference. Instead, I would like to get a type giving the guarantee that each possible instance contains an actual string (that is a string other than null, the empty string and a sequence of spaces).

  • use a default value, such as "N.A.", for the Value property. Doing so, even when an instance of NonEmptyString is created via the default constructor the wrapped string is actually a non empty string
  • add a private readonly field isInitialized, whose default value is false, in order to track whether the right constructor has been called (the field is set to true only in the constructor overload having the string parameter). Doing so it is possible to add a check at the beginning of each type member, so that an InvalidOperationException is raised each time the programmer creates an instance via the default constructor and tries to use it in his code.

If NonEmptyString were be defined as a class it would be useless, because each piece of code receiving an instance of NonEmptyString would have to check whether the instance contains a null reference. Instead, I would like to get a type giving the guarantee that each possible instance contains an actual string (that is a string other than null, the empty string and a sequence of spaces).

Rollback to Revision 4
Source Link
Vogel612
  • 25.5k
  • 7
  • 59
  • 141

UPDATE 27th SEPTEMBER 2019

After carefully reading all the answers to my question and thinking about the role of structs in C#, I realised that the type I came up with it's not useful to solve my problem.

My initial idea was to design this type as a struct in order to overcome the problem of string nullability. But this is actually a trick, not a carefully thought design decision.

From a certain point of view the idea of treating a string as a structure can be acceptable, because strings have a value type semantic in C#: they are compared by value by default and they overload the == operator accordingly. Furthermore strings are immutable and the C# structs are usually immutable types. But strings lack one important characteristic of structus: they don't rapresent a single primitive value (like a boolean value for instance, or an integer number). Instead a string is actually a sequence of single primitive values (the characters composing the string itself). This is probably one of the reason for which strings are designed as reference types while characters are designed as value types.

Structs have another important characteristic: each possible value, including the default value (the value composed by "all zeros for all the struct fields"), must have sense and be semantically correct for the struct itself. For instance false is the default value of System.Boolean and it makes perfectly sense as a boolean value and the same holds true for the value 0 which is the default value for the System.Int32 struct.

Conversely, the default value for my strucut is an instance of NonEmptyString which basically wraps a null string. This doesn't make sense from a semantic standpoint because you have a type which states I'm a string and you can trust that I always have a value neither null nor composed only by white spaces, but at the same time it exists one value of that type which represents a null reference. This is a contradiction and have some severe side effects.

Just to name a couple of them, if you have a class having a field of type NonEmptyString then the value contained in that field by default (prior to any initialization) is a value which doesn't make sense for the type NonEmptyString itself. Another scenario is a code like the following:

var strings = new NonEmptyString[10];

Doing so you will end up with an array containing 10 items whose value is a non sense for their type.

All the possible workarounds I came up with are simply tricks which have the only effect of creating a type complicated to be used. For instance, imagine of throwing each time an instance of NonEmptyString whose value is default(NonEmptyString) is used (this is one pissible solution I suggested in own question). The net result of this is having a non reliable type: each time someone pass you an instance of NonEmptyString you will have to ask yourself "is this a valid instance ?" or similarly "can I safely use this instance ?".

Probably the best solution for the problem I tried to solve by using the NonEmptyString struct is designing it as a class instead and waiting for C# 8 in order to use the nullable reference type feauture and get read of the annoying problem of dereferencing null references.

UPDATE 27th SEPTEMBER 2019

After carefully reading all the answers to my question and thinking about the role of structs in C#, I realised that the type I came up with it's not useful to solve my problem.

My initial idea was to design this type as a struct in order to overcome the problem of string nullability. But this is actually a trick, not a carefully thought design decision.

From a certain point of view the idea of treating a string as a structure can be acceptable, because strings have a value type semantic in C#: they are compared by value by default and they overload the == operator accordingly. Furthermore strings are immutable and the C# structs are usually immutable types. But strings lack one important characteristic of structus: they don't rapresent a single primitive value (like a boolean value for instance, or an integer number). Instead a string is actually a sequence of single primitive values (the characters composing the string itself). This is probably one of the reason for which strings are designed as reference types while characters are designed as value types.

Structs have another important characteristic: each possible value, including the default value (the value composed by "all zeros for all the struct fields"), must have sense and be semantically correct for the struct itself. For instance false is the default value of System.Boolean and it makes perfectly sense as a boolean value and the same holds true for the value 0 which is the default value for the System.Int32 struct.

Conversely, the default value for my strucut is an instance of NonEmptyString which basically wraps a null string. This doesn't make sense from a semantic standpoint because you have a type which states I'm a string and you can trust that I always have a value neither null nor composed only by white spaces, but at the same time it exists one value of that type which represents a null reference. This is a contradiction and have some severe side effects.

Just to name a couple of them, if you have a class having a field of type NonEmptyString then the value contained in that field by default (prior to any initialization) is a value which doesn't make sense for the type NonEmptyString itself. Another scenario is a code like the following:

var strings = new NonEmptyString[10];

Doing so you will end up with an array containing 10 items whose value is a non sense for their type.

All the possible workarounds I came up with are simply tricks which have the only effect of creating a type complicated to be used. For instance, imagine of throwing each time an instance of NonEmptyString whose value is default(NonEmptyString) is used (this is one pissible solution I suggested in own question). The net result of this is having a non reliable type: each time someone pass you an instance of NonEmptyString you will have to ask yourself "is this a valid instance ?" or similarly "can I safely use this instance ?".

Probably the best solution for the problem I tried to solve by using the NonEmptyString struct is designing it as a class instead and waiting for C# 8 in order to use the nullable reference type feauture and get read of the annoying problem of dereferencing null references.

added 3326 characters in body
Source Link

UPDATE 27th SEPTEMBER 2019

After carefully reading all the answers to my question and thinking about the role of structs in C#, I realised that the type I came up with it's not useful to solve my problem.

My initial idea was to design this type as a struct in order to overcome the problem of string nullability. But this is actually a trick, not a carefully thought design decision.

From a certain point of view the idea of treating a string as a structure can be acceptable, because strings have a value type semantic in C#: they are compared by value by default and they overload the == operator accordingly. Furthermore strings are immutable and the C# structs are usually immutable types. But strings lack one important characteristic of structus: they don't rapresent a single primitive value (like a boolean value for instance, or an integer number). Instead a string is actually a sequence of single primitive values (the characters composing the string itself). This is probably one of the reason for which strings are designed as reference types while characters are designed as value types.

Structs have another important characteristic: each possible value, including the default value (the value composed by "all zeros for all the struct fields"), must have sense and be semantically correct for the struct itself. For instance false is the default value of System.Boolean and it makes perfectly sense as a boolean value and the same holds true for the value 0 which is the default value for the System.Int32 struct.

Conversely, the default value for my strucut is an instance of NonEmptyString which basically wraps a null string. This doesn't make sense from a semantic standpoint because you have a type which states I'm a string and you can trust that I always have a value neither null nor composed only by white spaces, but at the same time it exists one value of that type which represents a null reference. This is a contradiction and have some severe side effects.

Just to name a couple of them, if you have a class having a field of type NonEmptyString then the value contained in that field by default (prior to any initialization) is a value which doesn't make sense for the type NonEmptyString itself. Another scenario is a code like the following:

var strings = new NonEmptyString[10];

Doing so you will end up with an array containing 10 items whose value is a non sense for their type.

All the possible workarounds I came up with are simply tricks which have the only effect of creating a type complicated to be used. For instance, imagine of throwing each time an instance of NonEmptyString whose value is default(NonEmptyString) is used (this is one pissible solution I suggested in own question). The net result of this is having a non reliable type: each time someone pass you an instance of NonEmptyString you will have to ask yourself "is this a valid instance ?" or similarly "can I safely use this instance ?".

Probably the best solution for the problem I tried to solve by using the NonEmptyString struct is designing it as a class instead and waiting for C# 8 in order to use the nullable reference type feauture and get read of the annoying problem of dereferencing null references.

UPDATE 27th SEPTEMBER 2019

After carefully reading all the answers to my question and thinking about the role of structs in C#, I realised that the type I came up with it's not useful to solve my problem.

My initial idea was to design this type as a struct in order to overcome the problem of string nullability. But this is actually a trick, not a carefully thought design decision.

From a certain point of view the idea of treating a string as a structure can be acceptable, because strings have a value type semantic in C#: they are compared by value by default and they overload the == operator accordingly. Furthermore strings are immutable and the C# structs are usually immutable types. But strings lack one important characteristic of structus: they don't rapresent a single primitive value (like a boolean value for instance, or an integer number). Instead a string is actually a sequence of single primitive values (the characters composing the string itself). This is probably one of the reason for which strings are designed as reference types while characters are designed as value types.

Structs have another important characteristic: each possible value, including the default value (the value composed by "all zeros for all the struct fields"), must have sense and be semantically correct for the struct itself. For instance false is the default value of System.Boolean and it makes perfectly sense as a boolean value and the same holds true for the value 0 which is the default value for the System.Int32 struct.

Conversely, the default value for my strucut is an instance of NonEmptyString which basically wraps a null string. This doesn't make sense from a semantic standpoint because you have a type which states I'm a string and you can trust that I always have a value neither null nor composed only by white spaces, but at the same time it exists one value of that type which represents a null reference. This is a contradiction and have some severe side effects.

Just to name a couple of them, if you have a class having a field of type NonEmptyString then the value contained in that field by default (prior to any initialization) is a value which doesn't make sense for the type NonEmptyString itself. Another scenario is a code like the following:

var strings = new NonEmptyString[10];

Doing so you will end up with an array containing 10 items whose value is a non sense for their type.

All the possible workarounds I came up with are simply tricks which have the only effect of creating a type complicated to be used. For instance, imagine of throwing each time an instance of NonEmptyString whose value is default(NonEmptyString) is used (this is one pissible solution I suggested in own question). The net result of this is having a non reliable type: each time someone pass you an instance of NonEmptyString you will have to ask yourself "is this a valid instance ?" or similarly "can I safely use this instance ?".

Probably the best solution for the problem I tried to solve by using the NonEmptyString struct is designing it as a class instead and waiting for C# 8 in order to use the nullable reference type feauture and get read of the annoying problem of dereferencing null references.

Tweeted twitter.com/StackCodeReview/status/1175333974916390912
edited tags; edited title
Link
200_success
  • 145.7k
  • 22
  • 191
  • 481
Loading
added 778 characters in body
Source Link
Loading
added 4 characters in body
Source Link
Loading
Source Link
Loading