I have read that C# allows local constants to be initialised to the null reference, for example:
const string MyString = null;
Is there any point in doing so however? What possible uses would this have?
My guess is because null is a valid value that can be assigned to reference types and nullable values types.
I can't see any reason to forbid this.
There might be some far off edge cases where this can be useful, for example with multi targeting and conditional compilation. IE you want to define a constant for one platform but define it as null for another due to missing functionality.
Ex, of possible usefull usage:
#IF (SILVELIGHT)
public const string DefaultName = null;
#ELSE
public const string DefaultName = "Win7";
#ENDIF
Indeed, you can initialize local const strings and readonly reference types to null, even though it seems to be redundant since their default value is null anyway.
However, the fact remains that null is a compile-time constant suitable enough to initialize strings and reference types. Therefore, the compiler would have to go out of its way in order to consider, identify and reject this special case, even though it's still perfectly valid from a language standpoint.
The merits of doing that would be disputable, and it probably wouldn't be worth the effort in the first place.
It could be used if you want to write code without keywords, if that strikes your fancy:
const string UninitializedSetting = null;
if (mySetting == UninitializedSetting)
{
Error("mySetting string not initialized");
}
Choosing to name a value (rather than using an in-place magic constant), using const, and setting to null are more or less orthogonal issues, although I agree that the venn diagram might have a very small area of overlap for the three :)
A case that I can think of is when you have as much or more throw-away data than you do code, but you want to ensure the values don't accidentally get changed while writing or maintaining your code. This situation is fairly common in unit tests:
[Test]
public void CtorNullUserName()
{
const string expectedUserName = null;
var user = new User(expectedUserName);
Assert.AreEqual(expectedUserName, user.Name, "Expected user name to be unchanged from ctor");
}
You could arguably structure such code in a plethora of ways that didn't involve assigning null to a const, but this is still a valid option.
This might also be useful to help resolve method overloading issues:
public class Something
{
public void DoSomething(int? value) { Console.WriteLine("int?"); }
public void DoSomething(string value) { Console.WriteLine("string"); }
}
// ...
new Something().DoSomething(null); // This is ambiguous, and won't compile
const string value = null;
new Something().DoSomething(value); // Not ambiguous
If you use constants, for example, for configuration of your application then why not? The null value can represent a valid state - e.g. that a logger is not installed. Also note that when you declare a local constant, you can initialize it to a value given by global constant (which may be a more interesting scenario).
EDIT: Another question is, what are good situations for using const anyway? For configuration, you'd probably want a configuration file and other variables usually change (unless they are immutable, but then readonly is a better fit...)
Besides the situations already pointed out, it may have to do with a quirk of the C# language. The C# Specification 3.0, section 8.5.2 states:
The type and constant-expression of a local constant declaration must follow the same rules as those of a constant member declaration (§10.4).
And within 10.4 reads as follows:
As described in §7.18, a constant-expression is an expression that can be fully evaluated at compile-time. Since the only way to create a non-null value of a reference-type other than string is to apply the new operator, and since the new operator is not permitted in a constant-expression, the only possible value for constants of reference-types other than string is null.
Related
Scenario
I have a class for declaring string constants used around a program:
public static class StringConstants
{
public const string ConstantA = "ConstantA";
public const string ConstantB = "ConstantB";
// ...
}
Essentially, it doesn't matter what the actual value of the constant is, as it used when assigning and consuming. It is just for checking against.
The constant names will be fairly self-explanatory, but I want to try and avoid using the same string values more than once.
What I would like to do
I know that nameof() is evaluated at compile-time, so it is entirely possible to assign the const string's value to the nameof() a member.
In order to save writing these magic strings out, I have thought about using the nameof() the constant itself.
Like so:
public static class StringConstants
{
public const string ConstantA = nameof(ConstantA);
public const string ConstantB = nameof(ConstantB);
// ...
}
Question...
I guess there is no real benefit of using the nameof(), other than for refactoring?
Are there any implications to using nameof() when assigning constants?
Should I stick to just using a hard-coded string?
Whilst I think the use of nameof is clever, I can think of a few scenarios where it might cause you a problem (not all of these might apply to you):
1/ There are some string values for which you can't have the name and value the same. Any string value starting with a number for example can't be used as a name of a constant. So you will have exceptions where you can't use nameof.
2/ Depending how these values are used (for example if they are names of values stored in a database, in an xml file, etc), then you aren't at liberty to change the values - which is fine until you come to refactor. If you want to rename a constant to make it more readable (or correct the previous developer's spelling mistake) then you can't change it if you are using nameof.
3/ For other developers who have to maintain your code, consider which is more readable:
public const string ConstantA = nameof(ContantA);
or
public const string ConstantA = "ConstantA";
Personally I think it is the latter. In my opinion if you go the nameof route then that might give other developers cause to stop and wonder why you did it that way. It is also implying that it is the name of the constant that is important, whereas if your usage scenario is anything like mine then it is the value that is important and the name is for convenience.
If you accept that there are times when you couldn't use nameof, then is there any real benefit in using it at all? I don't see any disadvantages aside from the above. Personally I would advocate sticking to traditional hard coded string constants.
That all said, if your objective is to simply to ensure that you are not using the same string value more than once, then (because this will give you a compiler error if two names are the same) this would be a very effective solution.
I think nameof() has 2 advantages over a literal strings:
1.) When the name changes, you will get compiler errors unless you change all occurences. So this is less error-prone.
2.) When quickly trying to understand code you didn't write yourself, you can clearly distinguish which context the name comes from. Example:
ViewModel1.PropertyChanged += OnPropertyChanged; // add the event handler in line 50
...
void OnPropertyChanged(object sender, string propertyName) // event handler in line 600
{
if (propertyName == nameof(ViewModel1.Color))
{
// no need to scroll up to line 50 in order to see
// that we're dealing with ViewModel1's properties
...
}
}
Using the nameof() operator with public constant strings is risky. As its name suggests, the value of a public constant should really be constant/permanent. If you have public constant declared with the nameof() and if you rename it later then you may break your client code using the constant. In his book Essential C# 4.0, Mark Michaelis points out: (Emphasis is mine)
public constants should be permanent because changing their value will
not necessarily take effect in the assemblies that use it. If an
assembly references constants from a different assembly, the value of
the constant is compiled directly into the referencing assembly.
Therefore, if the value in the referenced assembly is changed but the
referencing assembly is not recompiled, then the referencing assembly
will still use the original value, not the new value. Values that
could potentially change in the future should be specified as readonly
instead.
I have been working in C# for about 8 months so forgive me if this is dumb...
I have an enum that I will need the string value several times in a class. So I want to use Enum.GetName() to set it to a string variable which is no problem. I just do it like so...
private string MyEnumString = Enum.GetName(typeof(MyEnum), MyEnum.Name);
And it works just fine.
But I tried to protect it a little better because this particular Enum is more important that all the others and it would not be good if I accidentally changed the string value somehow so I tried to make it const like this.
private const string MyEnumString = Enum.GetName(typeof(MyEnum), MyEnum.Name);
To my eyes this seems fine as it should all be known at compile time.
But Visual Studio 2013 Throws an error saying the "Cannot resolve symbol GetName". I know it works when it is not marked "const".
So this leads me with two questions about this?
Why does it loose reference to the GetName enum? (After a bit of research I suspect it is something to do with GetName being a method and not a property of the Enum class but the error message just does not make sense to me)
And Finally is there a way to read the Name of MyEnum.Name to a const string other than what I am doing?
Just make it readonly:
private readonly string MyEnumString = Enum.GetName(typeof(MyEnum), MyEnum.Name);
Then it can't be changed afterwards.
You can't assign the result of calling a method to a constant; C# just doesn't allow it - the compiler would have to be calling that method at compile time, possibly before it was even compiled (and not only would it have to generate the IL, it would have to use the JIT compiler to compile that IL).
Enum.GetName(typeof(MyEnum), MyEnum.Name); is calling a method, so you can't assign the result to a constant.
[EDIT] As Jon Skeet says in a comment above, you can use nameof if using C#6 or later (i.e. VS2015 or later):
private const string MyEnumString = nameof(MyEnum.Name);
nameof works because here you are not calling an arbitrary method, but you are instead using a compiler feature to access the name of a type.
You cannot use result of the method as constant, because method evaluation can occur only at runtime. The value of the constant must be known at compile time. In order for compiler to be able to evaluate that constant, it would need to know the semantics of Enum.GetName and execute it at compile time, which is not possible
You can mark it as static readonly instead. That way it will be set once per type where it is declared and it cannot be changed anymore at runtime.
It may not even be known at run-time:
From MSDN:
If multiple enumeration members have the same underlying value, the GetName method guarantees that it will return the name of one of those enumeration members. However, it does not guarantee that it will always return the name of the same enumeration member.
(emphasis added)
void Main()
{
Console.WriteLine (Enum.GetName(typeof(Test),Test.One));
}
public enum Test
{
Zero,
One,
Two,
Uno = 1,
Dos = 2,
}
I consistently get the output Uno for the program above.
The reason is it not known is because enums are compiled to the underlying value. The call above is essentially compiled to Enum.GetName(typeof(Test), 1). GetName looks for a member with that value to find the name. How it does that is apparently an implementation detail that may not product consistent results.
What you can use for a constant in C#6 and later is nameof:
private const string MyEnumString = nameof(MyEnum.Name);
To my surprise, this one compiles and runs:
class Program
{
static void Main()
{
DoSomething();
}
private const int DefaultValue = 2; // <-- Here, private.
public static void DoSomething(int value = DefaultValue)
{
Console.WriteLine(value);
}
}
The method is public whereas the default value "redirects" to a constant private variable.
My question:
What is/was the idea behind this "concept"?
My understanding (until today) was, that something public can only be used if all other "referenced" elements are also public.
Update:
I just ILSpy-decompiled my class to find:
static class Program
{
private static void Main()
{
Program.DoSomething(2);
}
private const int DefaultValue = 2;
public static void DoSomething(int value = 2)
{
Console.WriteLine(value);
}
}
So if the private constant as a default parameter is being done in e.g. a library, the user of the library still sees the default parameter.
What is/was the idea behind this "concept"?
The idea is that as const value is static and never changes - you can use it as default value for method's optional parameters same as you can use normal values. A quote from MSDN :
Each optional parameter has a default value as part of its definition. If no argument is sent for that parameter, the default value is used. A default value must be one of the following types of expressions:
a constant expression;
an expression of the form new ValType(), where ValType is a value
type, such as an enum or a struct;
an expression of the form default(ValType), where ValType is a value
type.
My understanding (until today) was, that something public can only be
used if all other "referenced" elements are also public
Well technically speaking it's correct. But in your scenario both members are accessible as they are defined in the same class however should const in our case be defined outside of class Program it'd be inaccessible inside class Program.
The name DefaultValue is private, but the number 2 is still the number 2.
Because DefaultValue is private, we cannot access Program.DefaultValue from outside of Program. Presumably we wouldn't particularly want to.
And because we've bothered to define DefaultValue at all, it's presumably something that we do care about when we are working on how Program works.
So when we come to define a default value for DoSomething there's presumably some logical reason why the value we want there happens to be the same as the value DefaultValue.
And as such, it's presumably beneficial to be able to use that constant there, for much the same reasons as we would find constants beneficial anywhere.
And since DefaultValue is just a Program-specific way of saying 2, there's no real reason why we can't.
Of course, the metadata would reflect this as 2 rather than the (meaningless to the outside) DefaultValue, but then that would hold if the const was public anyway (the metadata about default values gives only the value, not whether or not it related to any defined constants).
So there's no downside.
So considering that:
There's an advantage to the implementer.
There's no disadvantage to the user, over just a use of a literal 2.
Preventing it would have to introduce a special rule to be an exception to the rule that defined constants can be used anywhere a constant value from a literal can.
Why not?
When you use const, the compiler replaces all the occurrences of the variable with the actual value ,so your code is the same as this:
public static void DoSomething(int value = 2)
Constant variables are replaced at compile-time, so they never really exist in the produced assembly. So code using a constant is really identical to just using the constant value directly. The benefit is just that you can reuse the constant elsewhere and only need to change it in one location.
Now, since constants are always replaced at compile-time, the effect of making them public or private is also quite simple: It just affects what other type can access it at compile-time. So using a private constant for example can be helpful if you just want to keep that constant to the current type, whereas a public constant can be used across the whole application.
I would like to set a const string from Settings.
In case I would like to change in the future the program language, it is quite easy;
Just have to modify the appropriate settings!
When trying this:
private const string constString =
"-&" + Properties.Settings.Default.constStringText;
I get this error:
The property or indexer 'Properties.Settings.Default'
cannot be used in this context because it lacks the get accessor.
Any idea?
Since you intend to use this as the default value for an optional method argument, that is:
public void Foo(string something = constString)
{
//do something
}
This constString must be a compile-time constant. From the MSDN page for "Named and Optional Arguments":
A default value must be one of the following types of expressions:
a constant expression;
an expression of the form new ValType(), where ValType is a value type, such as an enum or a struct;
an expression of the form default(ValType), where ValType is a value type.
As such, there really is no way to read a value from a configuration file at runtime then use it for an optional argument.
One workaround would be to instead declare your constString as a readonly field:
private readonly string constString =
"-&" + Properties.Settings.Default.constStringText;
Then make your optional argument required and create a wrapping overload for your method that doesn't take that parameter. That overload in turn calls the old method with the default value resolved at runtime:
public void Foo(string something) //no longer optional
{
//do something
}
public void Foo()
{
Foo(constString); //calls the other overload with the default value
}
This error is in 99% of cases related to a wrong namespace.
You've probably generated some class in which you are using Properties.Settings.Default
Solution: check namespace in that class file. It must be the same as the name of the tag in App.config (Web.config) where that particular setting is stored.
While Chris Sinclair’s answer (a const member must have value type and be evaluable at compile-time, so use readonly) is correct, I should like to explain these restrictions and answer the implicit question what the compiler message means, albeit with the disappointing remark that seems to be simply an error in the compiler.
The error message
The property or indexer 'Properties.Settings.Default' cannot be used in this context because it lacks the get accessor.
This message suggests that the expression Properties.Settings.Default could be made acceptable by adding a getter (and maybe something else) — as far as I know, that is simply wrong. After all, on the one hand, as the asker assured us1, there was a getter, and on the other, as Chris explains, the reason the expression is invalid is that is not evaluable at compile-time, and never can be, given that it depends on the run-time configuration.
Presumably this message is intended for other situations, and has been used here by mistake.
1 I have also seen this, in MSVS 2013, when a default parameter value referred to a property which did have a getter – but at least it also reported “Default parameter value for '<parname>' must be a compile-time constant”.
The restriction to value types
The restriction of const members and default parameter values to value types (as at the C# 5.0 Language Specification, 2012) appears to be not entirely inevitable, but an understandable consequence of other language design decisions.
A reference type can have a constructor evaluable at compile-time, but this is not supported ; perhaps this is because the language offers no way of indicating that a referenced object is immutable, nor even the concept of immutability of reference type objects. (Remember: an immutable reference to an object need not be a reference to an immutable object!)
Delegate values referring to static methods can also be considered fully determined at compile-time, as would those bound to immutable objects, were that concept supported.
Immutable arrays as constant values sound fairly easy to support.
Constant members¹ and (I believe)² default parameter values are specified to be part of the ‘interface’ of the class, in the sense that their values are to be determined at compile time and hard-coded into generated code using that class.
Resolution of the problem
You can use ( static ) readonly constString instead of const constString, to make clear that while the value will not change, it is not determined until run-time, at class or object initialisation (as in Chris’s answer).
If you want to use the expression as a default value for an optional parameter, it must be a true compile-time constant, leaving you two possibilities:
Declare an overload, as in Chris’s answer, e.g.:
Foo() { Foo(Default); } Foo(string s) { Bar(s); }.
This will often be the simpler solution, but could clutter your code and interface if you have many such parameters and thus many overloads, all with documentation comments.
Use null as a convention for the default, and interpret that in your method:
Foo(string s = null) { Bar(s != null ? s : Default); }.
This obviously only works if null is not a supported parameter to Foo(string) and should definitely be clarified in documentation comments.
Maybe: apply the Optional attribute, as in this question: behaviour of Optional attribute:
Foo([Optional] string s) { Bar(etc.?); } .
I have not used or studied this – the documentation seemed rather sparse – but it seems tricky and to yield no more than default = null, unless perhaps null is a supported argument to Foo(string).
References
¹ Language Specification 5.0 §10.5.2.2 10.5.2.2 Versioning of constants and static readonly fields
² I recall reading this, but have not found it in the Language Specification.
I recently encountered this scenario, and while searching for a solution I stumbled on this page. Based on the example above, I was able to resolve my issue like this:
private static readonly String ConStr
= string.Format("Data Source={0};Initial Catalog={1}; User ID={2}; Password={3};",
Properties.Settings.Default.DataSource,
Properties.Settings.Default.Catalog,
Properties.Settings.Default.UserID,
Properties.Settings.Default.Password);
Just wanted to share.
It's quite annoying to test all my strings for null before I can safely apply methods like ToUpper(), StartWith() etc...
If the default value of string were the empty string, I would not have to test, and I would feel it to be more consistent with the other value types like int or double for example.
Additionally Nullable<String> would make sense.
So why did the designers of C# choose to use null as the default value of strings?
Note: This relates to this question, but is more focused on the why instead of what to do with it.
Why is the default value of the string type null instead of an empty
string?
Because string is a reference type and the default value for all reference types is null.
It's quite annoying to test all my strings for null before I can
safely apply methods like ToUpper(), StartWith() etc...
That is consistent with the behaviour of reference types. Before invoking their instance members, one should put a check in place for a null reference.
If the default value of string were the empty string, I would not have
to test, and I would feel it to be more consistent with the other
value types like int or double for example.
Assigning the default value to a specific reference type other than null would make it inconsistent.
Additionally Nullable<String> would make sense.
Nullable<T> works with the value types. Of note is the fact that Nullable was not introduced on the original .NET platform so there would have been a lot of broken code had they changed that rule.(Courtesy #jcolebrand)
Habib is right -- because string is a reference type.
But more importantly, you don't have to check for null each time you use it. You probably should throw a ArgumentNullException if someone passes your function a null reference, though.
Here's the thing -- the framework would throw a NullReferenceException for you anyway if you tried to call .ToUpper() on a string. Remember that this case still can happen even if you test your arguments for null since any property or method on the objects passed to your function as parameters may evaluate to null.
That being said, checking for empty strings or nulls is a common thing to do, so they provide String.IsNullOrEmpty() and String.IsNullOrWhiteSpace() for just this purpose.
You could write an extension method (for what it's worth):
public static string EmptyNull(this string str)
{
return str ?? "";
}
Now this works safely:
string str = null;
string upper = str.EmptyNull().ToUpper();
You could also use the following, as of C# 6.0
string myString = null;
string result = myString?.ToUpper();
The string result will be null.
Empty strings and nulls are fundamentally different. A null is an absence of a value and an empty string is a value that is empty.
The programming language making assumptions about the "value" of a variable, in this case an empty string, will be as good as initiazing the string with any other value that will not cause a null reference problem.
Also, if you pass the handle to that string variable to other parts of the application, then that code will have no ways of validating whether you have intentionally passed a blank value or you have forgotten to populate the value of that variable.
Another occasion where this would be a problem is when the string is a return value from some function. Since string is a reference type and can technically have a value as null and empty both, therefore the function can also technically return a null or empty (there is nothing to stop it from doing so). Now, since there are 2 notions of the "absence of a value", i.e an empty string and a null, all the code that consumes this function will have to do 2 checks. One for empty and the other for null.
In short, its always good to have only 1 representation for a single state. For a broader discussion on empty and nulls, see the links below.
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
NULL vs Empty when dealing with user input
Why the designers of C# chose to use null as the default value of
strings?
Because strings are reference types, reference types are default value is null. Variables of reference types store references to the actual data.
Let's use default keyword for this case;
string str = default(string);
str is a string, so it is a reference type, so default value is null.
int str = (default)(int);
str is an int, so it is a value type, so default value is zero.
The fundamental reason/problem is that the designers of the CLS specification (which defines how languages interact with .net) did not define a means by which class members could specify that they must be called directly, rather than via callvirt, without the caller performing a null-reference check; nor did it provide a meany of defining structures which would not be subject to "normal" boxing.
Had the CLS specification defined such a means, then it would be possible for .net to consistently follow the lead established by the Common Object Model (COM), under which a null string reference was considered semantically equivalent to an empty string, and for other user-defined immutable class types which are supposed to have value semantics to likewise define default values. Essentially, what would happen would be for each member of String, e.g. Length to be written as something like [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }. This approach would have offered very nice semantics for things which should behave like values, but because of implementation issues need to be stored on the heap. The biggest difficulty with this approach is that the semantics of conversion between such types and Object could get a little murky.
An alternative approach would have been to allow the definition of special structure types which did not inherit from Object but instead had custom boxing and unboxing operations (which would convert to/from some other class type). Under such an approach, there would be a class type NullableString which behaves as string does now, and a custom-boxed struct type String, which would hold a single private field Value of type String. Attempting to convert a String to NullableString or Object would return Value if non-null, or String.Empty if null. Attempting to cast to String, a non-null reference to a NullableString instance would store the reference in Value (perhaps storing null if the length was zero); casting any other reference would throw an exception.
Even though strings have to be stored on the heap, there is conceptually no reason why they shouldn't behave like value types that have a non-null default value. Having them be stored as a "normal" structure which held a reference would have been efficient for code that used them as type "string", but would have added an extra layer of indirection and inefficiency when casting to "object". While I don't foresee .net adding either of the above features at this late date, perhaps designers of future frameworks might consider including them.
Because a string variable is a reference, not an instance.
Initializing it to Empty by default would have been possible but it would have introduced a lot of inconsistencies all over the board.
If the default value of string were the empty string, I would not have to test
Wrong! Changing the default value doesn't change the fact that it's a reference type and someone can still explicitly set the reference to be null.
Additionally Nullable<String> would make sense.
True point. It would make more sense to not allow null for any reference types, instead requiring Nullable<TheRefType> for that feature.
So why did the designers of C# choose to use null as the default value of strings?
Consistency with other reference types. Now, why allow null in reference types at all? Probably so that it feels like C, even though this is a questionable design decision in a language that also provides Nullable.
Perhaps if you'd use ?? operator when assigning your string variable, it might help you.
string str = SomeMethodThatReturnsaString() ?? "";
// if SomeMethodThatReturnsaString() returns a null value, "" is assigned to str.
A String is an immutable object which means when given a value, the old value doesn't get wiped out of memory, but remains in the old location, and the new value is put in a new location. So if the default value of String a was String.Empty, it would waste the String.Empty block in memory when it was given its first value.
Although it seems minuscule, it could turn into a problem when initializing a large array of strings with default values of String.Empty. Of course, you could always use the mutable StringBuilder class if this was going to be a problem.
Since string is a reference type and the default value for reference type is null.
Since you mentioned ToUpper(), and this usage is how I found this thread, I will share this shortcut (string ?? "").ToUpper():
private string _city;
public string City
{
get
{
return (this._city ?? "").ToUpper();
}
set
{
this._city = value;
}
}
Seems better than:
if(null != this._city)
{ this._city = this._city.ToUpper(); }
Maybe the string keyword confused you, as it looks exactly like any other value type declaration, but it is actually an alias to System.String as explained in this question.
Also the dark blue color in Visual Studio and the lowercase first letter may mislead into thinking it is a struct.
Nullable types did not come in until 2.0.
If nullable types had been made in the beginning of the language then string would have been non-nullable and string? would have been nullable. But they could not do this du to backward compatibility.
A lot of people talk about ref-type or not ref type, but string is an out of the ordinary class and solutions would have been found to make it possible.