背景
我有一個 stats 物件,它有許多計數器作為屬性。計數器可以在應用程式的任何位置更新。stats 物件是一個單例類(它曾經具有型別為long
and的公共欄位int
)。這些欄位已使用 更新Interlocked.Increment
。
我將欄位更改為屬性并創建了一個名為 的新類InterlockedInt64
,以封裝對Increment
. 我將以前的 stats 物件復制到一個臨時檔案中以跟蹤增量。我使用該Clone
方法來做到這一點,因為它是一個類。
簡化代碼在這里:https ://dotnetfiddle.net/baEm8E (及以下)。
問題
如果InterlockedInt64
是一個結構,我就不需要這個Clone
方法。但是,如果我將其更改為結構,則Increment
不再起作用。
有人可以解釋背后的機制嗎?我只需要了解為什么使用long
包裝在自定義結構中沒有更新,但long
欄位是。我了解 struct 和 class 之間的區別以及使用類的所有原因。
using System;
using System.Globalization;
using System.Threading;
public class Program
{
public static void Main()
{
var test = new Test();
test.Counter.Increment();
Console.WriteLine($"Expected 1, got {test.Counter}");
test.Counter.Increment();
Console.WriteLine($"Expected 2, got {test.Counter}");
test.Counter.Increment();
Console.WriteLine($"Expected 3, got {test.Counter}");
Interlocked.Increment(ref test.AnotherCounter);
Interlocked.Increment(ref test.AnotherCounter);
Interlocked.Increment(ref test.AnotherCounter);
Console.WriteLine($"AnotherCounter {test.AnotherCounter}");
}
public class Test
{
public InterlockedInt64 Counter { get; init; } = new InterlockedInt64();
public long AnotherCounter;
}
//public class InterlockedInt64 // Works
public struct InterlockedInt64 // Does not work
{
private long _value;
public InterlockedInt64()
{
_value = 0;
}
public InterlockedInt64(long value)
{
_value = value;
}
public long Increment() => Interlocked.Increment(ref _value);
public long Decrement() => Interlocked.Decrement(ref _value);
public long Exchange(long newValue) => Interlocked.Exchange(ref _value, newValue);
public InterlockedInt64 Clone() => new(_value);
public static implicit operator InterlockedInt64(long v)
{
return new InterlockedInt64(v);
}
public static implicit operator long (InterlockedInt64 v)
{
return v._value;
}
public override string ToString() => _value.ToString(CultureInfo.CurrentCulture);
public string ToString(CultureInfo cultureInfo) => _value.ToString(cultureInfo);
}
}
uj5u.com熱心網友回復:
使用 時struct
,您必須處理它們的副本(struct
通過值傳遞,而不是通過參考傳遞):
// you get a copy of test.Counter which you Increment and then throw it away
// note, that original test.Counter (its backing field) is not changed
test.Counter.Increment();
// you get a copy of test.Counter (which is unchanged) and print it out
Console.WriteLine($"Expected 1, got {test.Counter}");
如果您堅持使用InterlockedInt64
being struct
,您可以嘗試處理對以下的參考struct
:
public class Test {
// Backing field
private InterlockedInt64 m_Counter = new InterlockedInt64();
// we want to return reference (not copy) of the m_Counter
public ref InterlockedInt64 Counter {
get {
// and we return reference to the original field (not its copy)
return ref m_Counter;
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/490588.html
上一篇:從字串構建Linq排序運算式會導致““system.int32”的運算式不能用于回傳型別“System.Object””