C# 的只读(类似“const”)函数参数

问题描述 投票:0回答:4

来自 C++ 背景,我习惯于将

const
关键字粘贴到函数定义中,以使对象以只读值传递。但是,我发现这在 C# 中是不可能的(如果我错了,请纠正我)。经过一番谷歌搜索后,我得出的结论是,创建只读对象的唯一方法是编写一个仅具有“get”属性的接口并将其传入。优雅,我必须说。

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
或制作只读函数参数而不添加其他属性或函数?

c# constants
4个回答
13
投票

我认为您可能正在寻找一种涉及两个接口的解决方案,其中一个接口从另一个接口继承:

public interface IReadableFoo
{
    IMyValInterface MyVal { get; }
}

public interface IWritableFoo : IReadableFoo
{
    IMyValInterface MyVal { set; }
}

public class Foo : IWritableFoo 
{
    private ConcreteMyVal _myVal;

    public IMyValInterface MyVal
    {
        get { return _myVal; }
        set { _myVal = value as ConcreteMyVal; }
    }
}

然后您可以声明其参数类型“告诉”它是否计划更改变量的方法:

public void SomeFunction(IReadableFoo fooVar)
{
    // Cannot modify fooVar, excellent!
}

public void SomeOtherFunction(IWritableFoo fooVar)
{
    // Can modify fooVar, take care!
}

这模仿了类似于 C++ 中常量的编译时检查。正如埃里克·利珀特(Eric Lippert)正确指出的那样,这与不变性“不”相同。但作为一名 C++ 程序员,我想你知道这一点。 顺便说一句,如果将类中属性的类型声明为

ConcreteMyVal

并单独实现接口属性,则可以实现稍微更好的编译时检查:


public class Foo : IWritableFoo { private ConcreteMyVal _myVal; public ConcreteMyVal MyVal { get { return _myVal; } set { _myVal = value; } } public IMyValInterface IReadableFoo.MyVal { get { return MyVal; } } public IMyValInterface IWritableFoo.MyVal { // (or use “(ConcreteMyVal)value” if you want it to throw set { MyVal = value as ConcreteMyVal; } } }

这样,setter只能在通过接口访问时抛出,而通过类访问时则不会抛出。


8
投票
in

关键字。使用

in
使参数和
 输入参数 并防止其在方法内部被更改。来自官方 C# 文档:

    in
  • - 指定此参数通过引用传递,但
     仅由被调用的方法读取
  • ref
  • - 指定此参数通过引用传递,并且可以由被调用的方法读取或写入。
  • out
  • - 指定此参数通过引用传递,且
    must
    由被调用的方法写入。

enter image description here


4
投票
const

或类似的关键字应用于 C# 中的参数。

但是,您可以使用接口来执行这些操作。从某种意义上说,界面很特殊,因为制作一个仅涵盖功能集特定部分的界面是非常有意义的。例如。想象一个堆栈类,它同时实现了 

IPopable

IPushable
。如果您通过
IPopable
接口访问实例,则只能从堆栈中删除条目。如果通过
IPushable
接口访问实例,则只能向堆栈添加条目。您可以通过这种方式使用接口来获得与您所要求的类似的东西。
    


2
投票

引用类型(对象)参数默认为 IN 参数。 但因为它们是引用,所以它们的方法副作用和属性访问是在方法外部对对象完成的。 该对象不必传递出去。 还是按照方法修改的。

但是,默认情况下,值类型(结构)参数也是 IN,并且不能对传入的元素产生副作用或属性修改。相反,它会在进入方法之前获得 COPIED ON WRITE。 当方法超出范围(方法结束)时,对该方法内部的任何更改都会终止。

不要仅仅为了满足这种需求而将类更改为结构。 这是一个坏主意。 但如果它们无论如何都应该是结构体,现在你就会知道了。

顺便说一句,一半的编程社区并没有正确理解这个概念,但他们认为他们理解了(事实上,我在几本书中发现了 C# 中参数方向问题的不准确之处)。 如果您想对我的陈述的准确性发表评论,请仔细检查以确保您知道自己在说什么。

© www.soinside.com 2019 - 2024. All rights reserved.