Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 强制函数输入参数不可变?_C#_Function_Parameters_Immutability - Fatal编程技术网

C# 强制函数输入参数不可变?

C# 强制函数输入参数不可变?,c#,function,parameters,immutability,C#,Function,Parameters,Immutability,我刚刚花了2天的大部分时间试图追踪一个bug,结果我意外地改变了作为函数输入提供的值 IEnumerable<DataLog> FilterIIR( IEnumerable<DataLog> buffer ) { double notFilter = 1.0 - FilterStrength; var filteredVal = buffer.FirstOrDefault()?.oilTemp ??

我刚刚花了2天的大部分时间试图追踪一个bug,结果我意外地改变了作为函数输入提供的值

    IEnumerable<DataLog>
    FilterIIR(
        IEnumerable<DataLog> buffer
    ) {
        double notFilter = 1.0 - FilterStrength;

        var filteredVal = buffer.FirstOrDefault()?.oilTemp ?? 0.0;
        foreach (var item in buffer)
        {
            filteredVal = (item.oilTemp * notFilter) + (filteredVal * FilterStrength);

            /* Mistake here!
            item.oilTemp = filteredValue;
            yield return item;
            */

            // Correct version!
            yield return new DataLog()
            {
                oilTemp = (float)filteredVal,
                ambTemp = item.ambTemp,
                oilCond = item.oilCond,
                logTime = item.logTime
            };
        }
    }
IEnumerable
过滤器(
IEnumerable缓冲区
) {
双notFilter=1.0-过滤器强度;
var filteredVal=buffer.FirstOrDefault()?.oilTemp±0.0;
foreach(缓冲区中的变量项)
{
filteredVal=(item.oilTemp*非过滤器)+(filteredVal*过滤器强度);
/*这里错了!
item.oilTemp=过滤数据值;
收益回报项目;
*/
//正确的版本!
返回新的数据日志()
{
油温=(浮子)过滤器深度,
ambTemp=项目ambTemp,
oilCond=项目。oilCond,
logTime=item.logTime
};
}
}
<>我的首选编程语言通常是C或C++,这取决于我认为更适合要求的(这是一个更适合C语言的更大程序的一部分)…… 现在,在C++中,我可以通过接受常数迭代器来防止这样的错误,因为在你检索它们时,你不能修改这些值(尽管我可能需要为返回值建立一个新容器)。我做了一些搜索,在C#中找不到任何简单的方法来实现这一点,有人知道不同吗

我原以为我可以创建一个
ireadonlynumerable
类,该类将
IEnumerable
作为构造函数,但后来我意识到,除非它在检索时复制值,否则实际上不会产生任何效果,因为基础值仍然可以修改

我有没有办法在将来避免这些错误?一些包装类,或者即使它是我想要保护的每个函数顶部的一个小代码段,任何东西都可以


目前我能想到的唯一可行的方法是为我需要的每个类定义一个
ReadOnly
版本,然后创建一个非只读版本,该版本继承和重载属性,并添加函数以提供同一类的可变版本。

问题在于这里并不是关于
IEnumerable
IEnumerable
s实际上是不可变的。您不能添加或删除其中的内容。可变的是您的
数据日志

因为
DataLog
是引用类型,
item
保存对原始对象的引用,而不是对象的副本。这一点,加上
DataLog
是可变的,允许您对传入的参数进行变异

因此,在高层次上,您可以:

  • 复制
    数据日志
    ,或
  • 使
    DataLog
    不可变
或者两者都有

您现在正在做的是“复制
数据日志
”。另一种方法是将
DataLog
class
更改为
struct
。这样,在将其传递给方法时,您将始终创建其副本(除非您使用
ref
标记参数)。因此,在使用此方法时要小心,因为它可能会悄悄地破坏假定按引用传递语义的现有方法

您还可以使
DataLog
不可变。这意味着删除所有设置器。或者,您可以添加名为
的方法WithXXX
,该方法返回仅具有一个不同属性的对象副本。如果您选择执行此操作,则您的
FilterIIR
将如下所示:

yield return item.WithOilTemp(filteredVal);
目前我能想到的唯一可行的方法是为我需要的每个类定义一个只读版本,然后使用一个非只读版本来继承和重载属性,并添加函数以提供同一类的可变版本


你实际上不需要这样做。请注意,
列表
显然是可变的。您可以编写一个名为
IReadOnlyDataLog
的接口。此接口将只有
数据日志的getter
。然后,让
FilterIIR
接受
IEnumerable
DataLog
实现
IReadOnlyDataLog
。这样,您就不会意外地改变
FilterIIR

中的
DataLog
对象。您是否考虑过将
DataLog
作为一个不可变的类。感谢@Salah的格式检查,尽管
实现了
并不是一个错误XD@juharr我在最后一段提到,除非这不是你的意思?我是说拥抱不可变,不要为类的可变版本而烦恼。@TheBeardedQuack,不客气。你是对的,这不是一个错误,但是拼写检查建议使用“已实现”,这就是我更改它的原因:)Hi@Sweeper,我没有想到使用接口方法,但这实际上就是我创建只读基类然后继承的意思。接口方法更整洁,因为我只有一个包含实现的位置。我知道,
IEnumerable
已经是不可变的了,也许我本可以更好地解释自己。当我在C++中有一个 const 容器时,它也会通过包含所有访问器返回常量引用来强制它所包含的项的不可变性。而 > x()//>代码方式很有意思,我认为这不会导致一个特别漂亮的代码基础。1接口的建议虽然我不知怎么完全错过了。@ TeaBudDead很好,C不是C++,所以你不能直接翻译所有的东西。将英文文本逐字翻译成德语会产生奇怪的德语,不是吗?:)你只需要将就一下语言所能提供的东西。依我看,
IReadOnlyDataLog
方法总体上也是最好的