6

I'm coding in C# for a group of people, I'm designing the signature of the methods to be coded and I need a way to ensure that people won't modify some parameters they will receive. They receive big structures so they are sent by reference, but I want they to consume the data without modifying the original values. But since the structures are big we don't want to make copies of them.

We can assume they don't want to change the data and we only need to protect them from making mistakes.

What solutions does C# offer?

Here's and example

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]
    }
}
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
javirs
  • 1,049
  • 26
  • 52
  • You should take a look at unit testing. – smoksnes Jan 26 '17 at 09:27
  • 3
    What?! `struct`-instances are passed by value. Anyway I don´t understand your problem. Can you show some sample-code that shows what you´re trying to do? – MakePeaceGreatAgain Jan 26 '17 at 09:27
  • I'm sorry, but your question is not very clear. Are you asking how to make sure your users will not change the values of arguments they send to your methods before they execute your methods? – Zohar Peled Jan 26 '17 at 09:28
  • 1
    You can´t prevent the person implementing a method to modify the arguments passed *by reference*. However as `struct´s are passed *by value* modifcations within that method don´t have any effect on the calling code. – MakePeaceGreatAgain Jan 26 '17 at 09:31
  • 1
    @himbrombeere Using a `struct` is fine unless it contains reference type members like `List<...>`, right? In that case adding/removing to/from the list would reflect in the calling code? – Thorsten Dittmar Jan 26 '17 at 09:34
  • if the DataSet is Huge and you definte it as struct then send it by copy .. arent you wasting resources in every iteration ? – javirs Jan 26 '17 at 09:34
  • 1
    Have a look at [this](http://stackoverflow.com/questions/10981888/const-function-parameter-in-c-sharp) It has already been asked and answered. or [this](http://stackoverflow.com/questions/114149/const-correctness-in-c-sharp) – Ol1v3r Jan 26 '17 at 09:52

3 Answers3

9

The pessimistic answer is None. If the want to change the data, they will. There is nothing you can do except making copies.


The optimistic answer assumes they don't want to change the data and you only need to protect them from making mistakes. Now that is possible:

Don't give them any setters. You did not say what your data looks like so I can give you only a vague description:

Do not expose the setters. Give them interfaces to your data classes that do not have setters, return collections as IEnumerable<> instead of the modifiable instance they are and so on. Make sure that through the interface they get to your data, your data cannot be modified.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • I added an exemple now, I like the ideas you are exposing, can you concrete a bit ? – javirs Jan 26 '17 at 09:33
  • @nvoigt someone can easily cast `IEnumerable<>` back to `List<>` and they can modify. Base class library has solution to all problems if you try to be optimistic !! :) – Akash Kava Jan 26 '17 at 10:10
  • @AkashKava This is C#... if you don't make a copy, "evil" people can just use reflection. Non-evil people are fine with `IEnumerable`. Any solution is not security, just being helpful so it's harder for the user to make mistakes. Casting an IEnumerable to List is not a mistake, it's intentional evil and falls into category one in my view. – nvoigt Jan 26 '17 at 10:45
  • @AkashKava And I hate those readonly fakes that .NET uses. They give you an `IList` and then throw exceptions half the time you actually use it as an `IList`. That's violating about any guideline I know about programming. Least surprise, ease-of-use, you name it. – nvoigt Jan 26 '17 at 10:48
  • @nvoigt, `IEnumerable` isn't same as `IList`, as `IList` has `Count` property, `IList` allows random access and `IEnumerable` allows only sequential access. `IList` is never necessarily modifiable. It isn't fake, it is good guideline on how to access "Sequentially" and "Randomly" I think they are genuine computing standards. Anyway you be happy with `IEnumerable` and try to access objects always sequentially and call random access as some violation, purely your choice. – Akash Kava Jan 26 '17 at 10:52
  • @AkashKava I would like an interface that gives read-only random access and Count. I don't like an interface that promises reading *and* writing and then crashes when I actually try. That's bullshit. In this case, it's crystal clear at compile time that it should be read-only. Passing something that poses as read/write but throws at runtime is not my style. – nvoigt Jan 26 '17 at 10:59
0

If you are looking for a const keywork like in C++ to prevent mutability of data then unfortunatly this does not exist.

What you can do is pass immutable classes (classes without data modifying properties or methods). -> Remove the public set; and just use read only methods

Bruno Belmondo
  • 2,299
  • 8
  • 18
0

Pass AsReadOnly() as parameters, no one can modify it.

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

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

Call as...

 SomeMethod( myList.AsReadOnly() );

So you can create class,

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

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



    bool SomeParam;
    Double lots of other params;
}
Akash Kava
  • 39,066
  • 20
  • 121
  • 167