3

According the docs:

You can't declare a ref struct as a member of a class or a normal struct.

But I managed to compile and run this:

public ref struct RefStruct
{
    public int value;
}
public class MyClass
{
    public RefStruct Item => default;
}    
...       

MyClass c = new MyClass();
Console.WriteLine(c.Item.value);

Now RefStruct is a ref struct and it is a member of a class. Is this statement wrong in some cases?

UPDATE Now the docs have been updated to a more precise description.

joe
  • 1,078
  • 2
  • 11
  • 30
  • Try changing the value in `c.Item` and you'll see what you're *actually* doing with your declaration :) – Luaan Jun 21 '19 at 06:34
  • Change the line to `public RefStruct Item { get; set; } = default;` Does that compile? What is the difference? What about `public RefStruct Item2() { return new RefStruct(); }`? Is your code more similar to the former or the latter? – mjwills Jun 21 '19 at 06:35
  • @mjwills no, it doesn't. I'm just complaining about the statement that `a ref struct can't be a member of a class`. But in fact, it can, semantically. – joe Jun 21 '19 at 06:38
  • 1
    The docs are incorrect - or at least imprecisely worded. The compiler error is more accurate - `Field or auto-implemented property cannot be of type 'Program.RefStruct' unless it is an instance member of a ref struct.`. The key principle here is that the compiler is **enforcing that the object lives on the stack**. It won't allow anything that results in the object living on the heap (whether that is a field or a field-backed property). I'll leave feedback on the page for you. – mjwills Jun 21 '19 at 06:40
  • @mjwills The error is confusing. Then how can I properly implement a `ref struct` non-auto property? Apparently, you can 't use a private field because that's not allowed. Then what can you do in the setter? only side effects? – joe Jun 21 '19 at 06:47
  • 2
    What part of the error is confusing? It is saying you can't have a field (whether an explicit field, or an implicit field behind an auto property) that is a ref struct. If you want to do that, the answer is **you can't**. ;P `Then what can you do in the setter?` Whatever you want (e.g. `new` up the ref struct, write to the console etc etc). **As long as you don't have an explicit or implicit field that is a ref struct.** Any case you can think of is covered 100% by that error message. It is very precisely and accurately worded (unlike the docs). – mjwills Jun 21 '19 at 06:48
  • @joe - you can store content of `ref struct` in setter and recreate it in getter (I've added it to my answer). – Alexei Levenkov Jun 21 '19 at 06:51
  • 2
    @SeM As I said - the docs are incorrect / imprecise. I pointed him to a better source of information, the error message itself. I have left them feedback to fix the docs. I have tried to explain the _principle_ that the compiler is enforcing. I am not sure what else I can say. – mjwills Jun 21 '19 at 06:52
  • The docs have now been improved - https://github.com/dotnet/docs/commit/80f0635717a17b117edfcc8d0a3160c76c6d145b . – mjwills Jul 07 '19 at 23:35

1 Answers1

5

It is not field of your class but rather return value of a property getter - which is fine as it is just function return value.

Note that "as a member of a class" usually includes properties and probably should be changed to "field of a class".

If you would try to declare it as a class field (either directly or indirectly via auto-implemented property) this will require part of the class (the data for ref struct) to be allocated on the stack and the rest allocated in manged heap.

The code in the question defines non-autoimplemented property. As result there is no need for compiler to automatically create hidden field of the property type in the class. So while property result type is ref struct it actually is not stored in the class and hence does not violate requirement for this ref struct type not be included into any class. Note that even making setter method would be fine by itself - storing value for that property would be tricky, but you can safely store content of the ref struct (public int value; as in the post) in set and recreate it in get.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • 1
    You can't create a property of `ref struct`, the compiler will give an error: _"Field or auto-implemented property cannot be of type 'RefStruct' unless it is an instance member of a ref struct."_ – SᴇM Jun 21 '19 at 06:35
  • 1
    Yea, I get it, I think the doc needs some improvements. @SᴇM I think you need to set the getter instead of using the auto one. – joe Jun 21 '19 at 06:35
  • @joe Sure if you create just a Property with getter returning default, it will be the same as you have declared. For example: `public RefStruct MyProperty { get { return default; } }` and it's equivalent to `RefStruct MyMethod() => default;`. – SᴇM Jun 21 '19 at 06:37
  • 1
    @SᴇM I think I've added explanation about your comment - see if that's enough. – Alexei Levenkov Jun 21 '19 at 06:50