Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read-only ("const"-like) function parameters of C#

Tags:

c#

constants

Coming from a C++ background, I'm used to sticking the const keyword into function definitions to make objects being passed in read-only values. However, I've found out that this is not possible in C# (please correct me if I'm wrong). After some Googling, I arrived at the conclusion that the only way to make a read-only object is to write an interface that only has 'get' properties and pass that in instead. Elegant, I must say.

public interface IFoo
{
  IMyValInterface MyVal{ get; }
}

public class Foo : IFoo
{
  private ConcreteMyVal _myVal;

  public IMyValInterface MyVal
  {
    get { return _myVal; }
  }
}

I would pass it into:

public void SomeFunction(IFoo fooVar)
{
  // Cannot modify fooVar, Excellent!!
}

This is fine. However, in the rest of my code, I would like to modify my object normally. Adding a 'set' property to the interface would break my read-only restriction. I can add a 'set' property to Foo (and not IFoo), but the signature expects an interface rather than a concrete object. I would have to do some casting.

// 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();

Is there a more elegant way of replicating const or making read-only function parameters without adding another property or a function?

like image 730
MarkP Avatar asked Sep 29 '10 23:09

MarkP


2 Answers

I think you may be looking for a solution involving two interfaces in which one inherits from the other:

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; }
    }
}

Then you can declare methods whose parameter type “tells” whether it plans on changing the variable or not:

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

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

This mimics compile-time checks similar to constness in C++. As Eric Lippert correctly pointed out, this is not the same as immutability. But as a C++ programmer I think you know that.

By the way, you can achieve slightly better compile-time checking if you declare the type of the property in the class as ConcreteMyVal and implement the interface properties separately:

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; }
    }
}

This way, the setter can only throw when accessed through the interface, but not when accessed through the class.

like image 180
Timwi Avatar answered Nov 03 '22 03:11

Timwi


First of all, you're correct: you cannot apply const or a similar keyword to parameters in C#.

However, you can use interfaces to do something along those lines. Interfaces are special in the sense, that it makes perfect sense to make an interface that only covers a specific part of a feature set. E.g. image a stack class, which implements both IPopable and IPushable. If you access the instance via the IPopable interface, you can only remove entries from the stack. If you access the instance via the IPushable interface, you can only add entries to the stack. You can use interfaces this way to get something similar to what you're asking for.

like image 3
Brian Rasmussen Avatar answered Nov 03 '22 02:11

Brian Rasmussen