1
  • If a struct has no field, you can access it without initializing it.
  • If a struct in the current project has a field, you will get the error "Use of unassigned local variable".
  • If a struct in a different project has a field, you can access it without initializing it.

This behavior seems weirdly inconsistent. What is the reason that accessing an uninitialized struct with a field in a different project does not cause an error, but if it were declared in the same project it does? Does the language specification address this?

Here is some sample code that demonstrates the various scenarios.

Project 1

static void Main()
{
    A a;
    a.ToString();    // No problem

    B<int> b;
    b.ToString();    // Use of unassigned local variable 'b'

    C<int> c;
    c.ToString();    // No problem
}

public struct A 
{
}

public struct B<T> 
{
    T[] a;
}

Project 2

public struct C<T>
{
    T[] a;
}

(Using VS2017 15.4.5)

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
  • 1
    I don't know if there's a section of the spec that mentions it but [this](http://blog.paranoidcoding.com/2016/02/15/are-private-members-api-surface.html) is some interesting reading. Basically we tend to think of private fields as implementation and not interface, but the rules for definite assignment in C# sort of require that struct's private fields be considered part of its interface. – Mike Zboray Nov 29 '17 at 22:42
  • Definitely related in some way. But the difference between reference assemblies and my example is that `Project 2` isn't a reference assembly. It's a proper assembly, and technically, all those private fields are in the assembly in some way (i.e. reflection would return them) – Kirk Woll Nov 29 '17 at 22:46
  • 1
    Yes that is a difference. This [github issue answers](https://github.com/dotnet/roslyn/issues/1722). It seems to be an intentional for backwards compatibility with older versions of the compiler. – Mike Zboray Nov 29 '17 at 22:50
  • @mikez that's a great link. Using that `strict` flag actually solves my underlying problem. If you post it as an answer (maybe include that flag directlly), would accept it straight away. – Kirk Woll Nov 29 '17 at 22:53

1 Answers1

1

This is an intentional decision on the part of the compiler authors to maintain backwards compatibility with older compilers that were not compliant with the specification. You can get the correct behavior by using the /features:strict flag when compiling.

See github issue #1722:

This was a very painful but intentional decision. This duplicates the (buggy) behavior of the previous compiler. I strongly recommend you add the compiler flag /features:strict to get the correct, specification-required (but not backward-compatible) behavior.

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • Nice, maybe add a bit about `strict` so you get the compiler error that you'd want. But +1, thanks! – Kirk Woll Nov 29 '17 at 22:54
  • Relatedly: https://stackoverflow.com/questions/37299549/how-to-specify-the-equivalent-of-featuresstrict-of-csc-exe-to-msbuild-exe-or – Kirk Woll Nov 30 '17 at 00:55