【发布时间】:2023-03-09 15:38:01
【问题描述】:
来自 C++ 背景,我习惯于将 const 关键字粘贴到函数定义中,以使对象以只读值传递。但是,我发现这在 C# 中是不可能的(如果我错了,请纠正我)。经过一番谷歌搜索,我得出的结论是,制作只读对象的唯一方法是编写一个只有“获取”属性的接口并将其传递进去。优雅,我必须说。
public interface IFoo
{
IMyValInterface MyVal{ get; }
}
public class Foo : IFoo
{
private ConcreteMyVal _myVal;
public IMyValInterface MyVal
{
get { return _myVal; }
}
}
我会把它传递给:
public void SomeFunction(IFoo fooVar)
{
// Cannot modify fooVar, Excellent!!
}
这很好。但是,在我的其余代码中,我想正常修改我的对象。向界面添加“设置”属性会打破我的只读限制。我可以向Foo(而不是IFoo)添加一个“设置”属性,但签名需要一个接口而不是一个具体的对象。我必须做一些选角。
// Add this to class Foo. Might assign null if cast fails??
set { _myVal = value as ConcreteMyVal; }
// Somewhere else in the code...
IFoo myFoo = new Foo;
(myFoo as Foo).MyFoo = new ConcreteMyVal();
有没有更优雅的方法来复制const 或在不添加其他属性或函数的情况下制作只读函数参数?
【问题讨论】:
-
只是评论你的第一句话:这不是“const”所做的。所指对象仍然是可变的。例如,考虑一个方法,它需要两个对类型 C 的引用,一个标记为 const,一个不标记。为两个引用传递对同一变量的引用。如果您对非常量引用进行变异,那么常量引用将观察到变异。 const 确实 not 提供了您可以依赖的只读保证。它也不会阻止可变对象的突变,因为它可以被丢弃。这与 C# 中的只读字段非常不同。
-
解决您的实际问题:这是一个令人困惑的问题。您似乎在说您想要(1)保证只读性和(2)改变对象的能力。那些是对立的。你不能同时拥有它们。您能否解释为什么您希望 SomeFunction 不能诱导突变?这是出于安全目的吗?是为了正确性吗?谁在提供 SomeFunction 的实现?如果是你,那你为什么需要它是 const 呢?如果您不想编写突变,那就不要。如果是其他人,那么你为什么要关心他们是否会引起突变?
-
@Eric:限制 SomeFunction 的功能是有意义的,即使我是编写它的人。它增加了编译时检查以验证意外错误。 (我敢肯定你以前犯过错误——你能不能想象自己犯了这种错误,你在不应该的时候不小心改变了一个变量?)我认为提问者不想保证读-only-ness,他只想要一个半保证,即此方法在通过参数访问它时不会改变此对象。
-
@Eric 我认为这里的想法是编译时错误发现,而不是安全性。我知道 C# 实现了所有“传统”方法来做到这一点,但似乎不太接受最近的方法——比如 Spec# 中正在研究的方法。
-
@Eric:“仅仅让接口提供读取功能可能还不够。” — 为了安全,当然不是!但是对于我没有犯过某种错误的保证,这是一个很好的开始。为什么存在“私人”访问修饰符?显然它不足以保证安全,因为反射可以颠覆它。这是否意味着它不应该存在,我们都应该使用“内部”来代替? “私有”的安全特性与“内部”有何不同?