Andrzej Gis
Andrzej Gis

Reputation: 14306

Is there a way to compare 2 ref structs by reference?

Recently I was wandering if it's possible to compare structs by reference. As reading a struct variable creates a copy of that variable, comparing standard structs by reference seems impossible. However using C# 7 refs would make more sense.

I defined 4 variables

MyStruct foo = new MyStruct(){SomeInt = 1};
ref MyStruct refFoo = ref foo;

MyStruct bar = new MyStruct() { SomeInt = 2 };
ref MyStruct refBar = ref foo;

Given MyStruct is a standard struct

struct MyStruct
{
    public int SomeInt { get; set; }
}

When I try this: var comparison1 = ReferenceEquals(refFoo, refBar);, I get warning saying that the value is always false, since I'm passing value types.

If I use C# 7 ref struct instead

ref struct MyStruct
{
    public int SomeInt { get; set; }
}

When I try this: var comparison1 = ReferenceEquals(refFoo, refBar);, I get a compilation error saying that MyStruct is not assignable to parameter type object. Same thing if I try: var comparison1 = ReferenceEquals(foo, bar);

The last case is when MyStruct is ref struct, but refFoo and refBar variables are declared without ref. (I get the same error as in the 2nd case)

static void Main(string[] args)
{
    MyStruct foo = new MyStruct(){SomeInt = 1};
    MyStruct refFoo = foo;

    MyStruct bar = new MyStruct() { SomeInt = 2 };
    MyStruct refBar = foo;

    var comparison1 = ReferenceEquals(refFoo, refBar);

}

ref struct MyStruct
{
    public int SomeInt { get; set; }
}

Upvotes: 2

Views: 1094

Answers (1)

Dudi Keleti
Dudi Keleti

Reputation: 2984

var comparison1 = ReferenceEquals(refFoo, refBar);, I get warning saying that the value is always false, since I'm passing value types

Each of the values will boxed so the result is always false.

var comparison1 = ReferenceEquals(refFoo, refBar);, I get a compilation error saying that MyStruct is not assignable to parameter type object. Same thing if I try: var comparison1 = ReferenceEquals(foo, bar);

ref can't be boxed or unboxed (Like @PetSerAl wrote).

The last case is when MyStruct is ref struct, but refFoo and refBar variables are declared without ref. (I get the same error as in the 2nd case)

Same as above.

Bonus question: Why only the 2nd and 3rd examples give me a compilation error?

I'm sure now you understand.

So, is there some sneaky way to compare structs by reference?

If you mean comparing addresses, here are some examples:

class Program
{
    struct Struct { public int Value { get; set; } }
    ref struct RefStruct { public int Value { get; set; } }

    static unsafe void Main(string[] args)
    {
        var @struct = new Struct { Value = 5 };
        var struct2 = @struct;
        ref Struct struct3 = ref @struct;
        Struct* p = &@struct;
        Struct* p2 = &struct2;
        Console.WriteLine($"struct  address is: {(int)p} struct  value is {p->Value}");
        Console.WriteLine($"struct2 address is: {(int)p2} struct2 value is {p2->Value}");
        fixed (Struct* p3 = &struct3)
        {
            Console.WriteLine($"struct3 address is: {(int)p3} struct3 value is {p3->Value}");
        }

        Console.WriteLine();
        Console.WriteLine($"struct and struct2 Unsafe.AreSame? {Unsafe.AreSame(ref @struct, ref struct2)}");
        Console.WriteLine($"struct and struct3 Unsafe.AreSame? {Unsafe.AreSame(ref @struct, ref struct3)}");
        Console.WriteLine();

        var structAsPointer = Unsafe.AsPointer(ref @struct);
        var struct2AsPointer = Unsafe.AsPointer(ref struct2);
        var struct3AsPointer = Unsafe.AsPointer(ref struct3);
        Console.WriteLine($"struct AsPointer and struct2 AsPointer are same? {structAsPointer == struct2AsPointer}");
        Console.WriteLine($"struct AsPointer and struct3 AsPointer are same? {structAsPointer == struct3AsPointer}");
        Console.WriteLine();

        var refStruct = new RefStruct { Value = 7 };
        var refStruct2 = refStruct;
        RefStruct* p4 = &refStruct;
        RefStruct* p5 = &refStruct2;
        Console.WriteLine($"refStruct  address is: {(int)p4}, refStruct  value is: {p4->Value}");
        Console.WriteLine($"refStruct2 address is: {(int)p5}, refStruct value is: {p5->Value}");

        ref RefStruct refStruct3 = ref refStruct;
        fixed (RefStruct* p6 = &refStruct3)
        {
            Console.WriteLine($"refStruct3 address is: {(int)p6}, refStruct3 value is: {p6->Value}");
            Console.WriteLine();
            Console.WriteLine($"refStruct and refStruct2 are same? {&refStruct == &refStruct2}");
            Console.WriteLine($"refStruct and refStruct3 are same? {&refStruct == p6}");
        }
    }
}

Upvotes: 1

Related Questions