我可以防止用户在C#中修改参数吗?

6
我正在为一群人编写C#代码,我正在设计要编码的方法的签名,并且我需要一种方法来确保人们不会修改他们将收到的某些参数。 他们会收到大型结构,因此它们是通过引用发送的,但是我希望他们在不修改原始值的情况下使用数据。但是由于结构很大,我们不想复制它们。 我们可以假设他们不想改变数据,我们只需要保护他们免受犯错误的影响。 C# 提供了什么解决方案? 以下是一个例子。
class MyDataBlok {
    List<double> samples;
    int someParams;
    double lots of other params
    }

class MySetOfDataBlock
{
    List<MyDataBlock> DataSet;
    bool SomeParam;
    Double lots of other params;
}

class MethodsToBeCoded
{
    ProcessSetOfData( /*some tag defining data as protected*/ MySetOfDataBlock data)
    {
         //Here I want code that uses data without modifying data
         // nor the content on any data.DataSet[i]
    }
}

你应该看一下单元测试。 - smoksnes
3
什么?'struct'实例是按值传递的。无论如何,我不明白你的问题。你能展示一些示例代码来说明你正在尝试做什么吗? - MakePeaceGreatAgain
1
你无法阻止实现方法的人通过引用修改传递的参数。但是,由于结构体是按值传递的,因此该方法中的修改不会对调用代码产生任何影响。 - MakePeaceGreatAgain
1
@himbrombeere 如果一个 struct 包含像 List<...> 这样的引用类型成员,那么使用它就没问题了吗?在这种情况下,向列表中添加/删除元素会反映在调用代码中吗? - Thorsten Dittmar
1
请看这个。它已经被提问和回答过了,或者看看这个 - Ol1v3r
显示剩余2条评论
3个回答

9
悲观的答案是没有。如果他们想要更改数据,他们就会这样做。除了制作副本之外,您无法做任何事情。
乐观的答案认为他们不想要更改数据,您只需要保护他们免受犯错的影响。现在这是可能的:
不要给他们任何setter。由于您没有说明数据的样子,因此我只能给您一个模糊的描述:
不要公开setter。给他们访问您的数据类的接口,这些接口没有setter,将集合作为IEnumerable<>返回而不是可修改的实例等等。确保通过接口访问您的数据时,您的数据无法被修改。

我现在添加了一个例子,我喜欢你所提出的想法,你能具体一点吗? - javirs
@nvoigt,有人可以轻松地将 IEnumerable<> 强制转换回 List<> 并进行修改。如果你乐观一点,基类库对所有问题都有解决方案!! :) - Akash Kava
如果你不进行拷贝, "邪恶" 的人就可以使用反射。非邪恶的人可以使用 IEnumerable。任何解决方案都不是安全的,只是有助于让用户更难犯错误。将 IEnumerable 强制转换为 List 不是一个错误,而是故意为之的恶意行为,并且在我看来属于第一类。 - nvoigt
@AkashKava 我讨厌.NET使用的那些只读假设。它们给你一个 IList,但大多数情况下当你将其用作 IList 时会抛出异常。这违反了我所知道的关于编程的任何指南。最少惊喜原则、易用性,你随便怎么说都可以。 - nvoigt
@nvoigt,“IEnumerable”和“IList”不同,“IList”有“Count”属性,允许随机访问,“IEnumerable”只允许顺序访问。“IList”并不一定可修改。这并不是虚假的,它是如何“顺序”和“随机”访问的良好指导方针,我认为它们是真正的计算标准。无论如何,您可以使用“IEnumerable”,并始终顺序访问对象并将随机访问称为某些违规行为。这完全是您的选择。 - Akash Kava
@AkashKava,我想要一个提供只读的随机访问和计数的接口。我不喜欢一个声称可以读写但实际上在尝试时崩溃的接口。那太扯了。在这种情况下,在编译时就应该明确它是只读的。传递一个伪装成可读写但在运行时抛出异常的东西不符合我的风格。 - nvoigt

0

如果你正在寻找像C++中的const关键字来防止数据可变性的方法,那么不幸的是这种方法并不存在。

你可以做的是传递不可变类(没有修改数据属性或方法的类)。-> 移除公共设置;只使用只读方法


0

AsReadOnly()作为参数传递,就不会有人可以修改它。

https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx

 public void SomeMethod(IList<SomeData> list){
       ....
 }

称为...

 SomeMethod( myList.AsReadOnly() );

所以你可以创建类,

Class MySetOfDataBlock
{
    private List<MyDataBlock> _DataSet;
       = new List<MyDataBlock>();

    public IList<MyDataBlock> DataSet{
        get{
           return _DataSet.AsReadOnly();
        }
    }



    bool SomeParam;
    Double lots of other params;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接