6

Example 1

private const string _DefaultIconPath = _IconsPath + "default.ico";
private const string _IconsPath = "Icons/";

Value of these strings at runtime:

  • _DefaultIconPath: "Icons/default.ico"
  • _IconsPath: "Icons/"

Example 2

private readonly string _DefaultIconPath = _IconsPath + "default.ico";
private readonly string _IconsPath = "Icons/";

Compile time error:

A field initializer cannot reference the non-static field, method, or property '_IconsPath'

Example 3

private static readonly string _DefaultIconPath = _IconsPath + "default.ico";
private static readonly string _IconsPath = "Icons/";

Value of these strings at runtime:

  • _DefaultIconPath: "default.ico" (_IconsPath evaluated to null)
  • _IconsPath: "Icons/"

Question

Why doesn't the compiler throw a compilation error in example 3 similar to example 2?

The order of the declaration matters in the case of static readonly field definitions, but not in the case of const field definitions.

Edit:

I understand why the strings are initialized to those specific values. What I don't understand is why Example 2 throws a compilation error, forcing initialization to occur in a constructor rather than in the declaration of the variables (which makes perfect sense), but Example 3 doesn't behave in the same manner. Wouldn't it make sense to throw the same compilation error forcing the initialization to occur in a static constructor?


Another Example

private static string test = test2;
private static string test2 = test;

This example demonstrates what I'm trying to explain. The compiler could force initialization of static state in a static constructor (as is does for instance variables). Why does the compiler allow it (or why does the compiler disallow this for instance variables)?

Dylan Meador
  • 2,381
  • 1
  • 19
  • 32
  • You're asking why the compiler allows or disallows things - that's simply because it's following the language specification. Are you *really* trying to ask for the motivation behind the language design? – Jon Skeet Aug 09 '12 at 20:57
  • 1
    @JonSkeet Yes, I guess that's what I'm really after. I thought there might be a simple explanation. – Dylan Meador Aug 09 '12 at 21:04

3 Answers3

0

There are two unrelated problems.

1. Compilation Error

Static members do not require an instance of a class to obtain the values. This is why referencing a static member from a static member does not cause problems.

When initializing instance members, you cannot reference this when attempting to initialize members unless you do so from the constructor.

Because you have not marked the fields in Example 2 as static, you must first instantiate an instance of whatever object contains them prior to referencing those members.

Just because they are readonly does not mean that they are static. Readonly fields can be instantiated in their declaration or the constructor of the class, but they are not shared across all instances of the class, nor can they be accessed without proper instantiation (assuming they aren't explicitly made static like Example 3).

2. Null Value

The reason _IconsPath is null in Example 3 is because the fields are declared and instantiated sequentially. Reverse the order and you'll see that it is no longer null.

Justin Skiles
  • 9,373
  • 6
  • 50
  • 61
  • The examples are similar. The compiler allows readonly field initialization for static variables, but not instance variables. **Why?** – Dylan Meador Aug 09 '12 at 19:45
  • It most certainly does allow readonly initializations for instance variables, but not if the intialization contains another instance variable because you don't have an instance of that class! – Justin Skiles Aug 09 '12 at 19:47
  • So it doesn't allow initialization of an instance field if it contains a reference to another instance field. So **why** does it allow the initialization of a static field if it contains a reference to another static field. That's my question. – Dylan Meador Aug 09 '12 at 19:52
  • Because that's how statics work. Static members do not require instantiation. Read: http://msdn.microsoft.com/en-us/library/79b3xss3%28v=vs.80%29.aspx – Justin Skiles Aug 09 '12 at 19:53
0

Example 3 uses static variables and so it is allowed.

Example 2 fails because C# does not allow a variable initializer to refer the instance being created. Refer Jon Skeet's explanation here.

You could do this instead:

public class YourClass {
  private readonly string _IconsPath;
  private readonly string _DefaultIconsPath;

  public YourClass() {
    _IconsPath = "Icons/";
    _DefaultIconPath = _IconsPath + "default.ico";
  }
}
Community
  • 1
  • 1
Channs
  • 2,091
  • 1
  • 15
  • 20
  • But **why** is it allowed. I know how to fix this problem; I'm trying to understand why the compiler allows it. – Dylan Meador Aug 09 '12 at 19:43
  • @Dylan - As you would expect, static members are referenced by the class and not by instance. Static members are available before you access them, the exact implementation differs based on the language ([this](http://stackoverflow.com/questions/3965976/when-do-static-variables-get-initialized-in-c) SO thread throws more light and provides good references). So, just like `Colors.Red` is always available, `YourClass.StaticMember` is always available. Hope this makes sense. – Channs Aug 09 '12 at 19:50
0

In example 2 '_IconsPath' isn't initialized, and can not be used.

In example 3, you are accessing a static field (as you know). It perfectly fine says MSDN A static method, field, property, or event is callable on a class even when no instance of the class has been created.

See it here

Update: Example 3: It's the same as:

private static readonly string _DefaultIconPath = MyStaticClass._IconsPath + "default.ico";
private static readonly string _IconsPath = "Icons/";

The point is that your not using a field (belove that isn't initialized, you are using an ("other"/"new") static class (That dosn't have to be create before you used it in a static way).

radbyx
  • 9,352
  • 21
  • 84
  • 127
  • I understand all of that, but notice how `MyStaticClass._IconsPath` evaluates to `null`. If those were `const` instead of `static readonly`, the values would turn out as expected. Since instance fields force initialization to occur in the constructor (for this scenario), they reduce the chance for a problem to occur. The same can't be said for `static` fields. – Dylan Meador Aug 09 '12 at 20:41
  • 1) It evaluates to null because it isn't initialized until after it is used. 2) `const` must be intialized at declaration, unlike `static`. 3) "Instance" fields do not force initialization to occur in the constructor. – Justin Skiles Aug 09 '12 at 20:47
  • @jskiles1 They do in scenarios like this. See Example 2. – Dylan Meador Aug 09 '12 at 20:50
  • 1
    At this point I'm lost as to what you're even asking. People have provided you with far more than enough links and information to understand the differences between instance and static. A link in one of the responses provides an answer to your instance initialization confusion. – Justin Skiles Aug 09 '12 at 20:54