有没有办法通过引用比较 2 个 ref 结构?
Posted
技术标签:
【中文标题】有没有办法通过引用比较 2 个 ref 结构?【英文标题】:Is there a way to compare 2 ref structs by reference? 【发布时间】:2019-06-27 14:30:54 【问题描述】:最近我在徘徊是否可以通过引用比较结构。由于读取结构变量会创建该变量的副本,因此通过引用比较标准结构似乎是不可能的。但是使用 C# 7 ref
s 会更有意义。
我定义了 4 个变量
MyStruct foo = new MyStruct()SomeInt = 1;
ref MyStruct refFoo = ref foo;
MyStruct bar = new MyStruct() SomeInt = 2 ;
ref MyStruct refBar = ref foo;
鉴于 MyStruct 是一个标准结构
struct MyStruct
public int SomeInt get; set;
当我尝试这个:var comparison1 = ReferenceEquals(refFoo, refBar);
时,我收到 警告 说该值始终为 false,因为我正在传递值类型。
如果我改用 C# 7 ref struct
ref struct MyStruct
public int SomeInt get; set;
当我尝试这个:var comparison1 = ReferenceEquals(refFoo, refBar);
,我得到一个编译错误,说MyStruct
不能分配给参数类型object
。如果我尝试同样的事情:var comparison1 = ReferenceEquals(foo, bar);
最后一种情况是MyStruct
是ref struct
,但是refFoo
和refBar
变量声明时没有ref
。 (我得到与第二种情况相同的错误)
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;
那么,是否有一些偷偷摸摸的方法来通过引用比较结构?
额外问题:为什么只有第 2 和第 3 个示例给我一个汇编
错误?
【问题讨论】:
为什么只有第二个例子给我一个编译错误?因为ref struct
不能装箱。
@PetSerAl 不知道。这就是我要问的部分内容:)
按照我的理解,ref structs 只需要在堆栈上,您无法获得对它的引用,就像您无法获得对堆栈分配数组的引用一样。这里的区别是编译器没有暴露幕后存在的指针。
@JeffMercado 谢谢,这可以解释“bouns 问题”。
System.Runtime.CompilerServices.Unsafe.AreSame
【参考方案1】:
var comparison1 = ReferenceEquals(refFoo, refBar);
,我收到警告说该值始终为 false,因为我正在传递值类型
每个值都会被装箱,所以结果总是假的。
var comparison1 = ReferenceEquals(refFoo, refBar);
,我收到一个编译错误,指出 MyStruct 不能分配给参数类型对象。如果我尝试同样的事情:var comparison1 = ReferenceEquals(foo, bar);
ref
不能装箱或拆箱(就像@PetSerAl 写的那样)。
最后一种情况是 MyStruct 是 ref struct,但是 refFoo 和 refBar 变量声明时没有 ref。 (我得到与第二种情况相同的错误)
同上。
额外问题:为什么只有第二个和第三个示例给我一个编译错误?
我相信你现在明白了。
那么,有没有一些偷偷摸摸的方法来通过引用比较结构?
如果您的意思是比较地址,这里有一些例子:
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");
【讨论】:
以上是关于有没有办法通过引用比较 2 个 ref 结构?的主要内容,如果未能解决你的问题,请参考以下文章
在 `System.Windows.Forms` 控件中没有 `ref` 关键字的情况下,如何通过引用传递