我知道这可能有点晚了。但是对于仍在寻找其他方法的人来说,可能有另一种方法可以绕过 C# 标准的这个限制。我们可以编写包装类 ReadOnly<T> where T : struct。隐式转换为基类型 T。但仅显式转换为 wrapper<T> 类。如果开发人员尝试将隐式设置为 ReadOnly<T> 类型的值,这将强制编译器错误。我将在下面展示两种可能的用途。
USAGE 1 需要更改调用者定义。此用法仅用于测试“TestCalled”函数代码的正确性。在发布级别/构建时,您不应该使用它。因为在大规模的数学运算中可能会过度使用转换,并使您的代码变慢。我不会使用它,但仅出于演示目的,我已发布它。
我建议的 USAGE 2 在 TestCalled2 函数中演示了 Debug vs Release 使用。使用这种方法时,TestCaller 函数也不会进行转换,但它需要使用编译器条件对 TestCaller2 定义进行更多编码。您可以在调试配置中注意到编译器错误,而在发布配置中,TestCalled2 函数中的所有代码都将成功编译。
using System;
using System.Collections.Generic;
public class ReadOnly<VT>
where VT : struct
{
private VT value;
public ReadOnly(VT value)
{
this.value = value;
}
public static implicit operator VT(ReadOnly<VT> rvalue)
{
return rvalue.value;
}
public static explicit operator ReadOnly<VT>(VT rvalue)
{
return new ReadOnly<VT>(rvalue);
}
}
public static class TestFunctionArguments
{
static void TestCall()
{
long a = 0;
// CALL USAGE 1.
// explicite cast must exist in call to this function
// and clearly states it will be readonly inside TestCalled function.
TestCalled(a); // invalid call, we must explicit cast to ReadOnly<T>
TestCalled((ReadOnly<long>)a); // explicit cast to ReadOnly<T>
// CALL USAGE 2.
// Debug vs Release call has no difference - no compiler errors
TestCalled2(a);
}
// ARG USAGE 1.
static void TestCalled(ReadOnly<long> a)
{
// invalid operations, compiler errors
a = 10L;
a += 2L;
a -= 2L;
a *= 2L;
a /= 2L;
a++;
a--;
// valid operations
long l;
l = a + 2;
l = a - 2;
l = a * 2;
l = a / 2;
l = a ^ 2;
l = a | 2;
l = a & 2;
l = a << 2;
l = a >> 2;
l = ~a;
}
// ARG USAGE 2.
#if DEBUG
static void TestCalled2(long a2_writable)
{
ReadOnly<long> a = new ReadOnly<long>(a2_writable);
#else
static void TestCalled2(long a)
{
#endif
// invalid operations
// compiler will have errors in debug configuration
// compiler will compile in release
a = 10L;
a += 2L;
a -= 2L;
a *= 2L;
a /= 2L;
a++;
a--;
// valid operations
// compiler will compile in both, debug and release configurations
long l;
l = a + 2;
l = a - 2;
l = a * 2;
l = a / 2;
l = a ^ 2;
l = a | 2;
l = a & 2;
l = a << 2;
l = a >> 2;
l = ~a;
}
}