How to make a reference type property “readonly”

后端 未结 8 642
青春惊慌失措
青春惊慌失措 2020-12-28 20:23

I have a class Bar with a private field containing the reference type Foo. I would like to expose Foo in a public property, but I do n

相关标签:
8条回答
  • 2020-12-28 20:38

    You can actually reproduce the behaviour of C++ const in C# - you just have to do it manually.

    Whatever Foo is, the only way the caller can modify its state is by calling methods on it or setting properties.

    For example, Foo is of type FooClass:

    class FooClass
    {
        public void MutateMyStateYouBadBoy() { ... }
    
        public string Message
        {
            get { ... }
            set { ... }
        }
    }
    

    So in your case, you're happy for them to get the Message property, but not set it, and you're definitely not happy about them calling that method.

    So define an interface describing what they're allowed to do:

    interface IFooConst
    {
        public string Message
        {
            get { ... }
        }
    }
    

    We've left out the mutating method and only left in the getter on the property.

    Then add that interface to the base list of FooClass.

    Now in your class with the Foo property, you have a field:

    private FooClass _foo;
    

    And a property getter:

    public IFooConst Foo
    {
        get { return _foo; }
    }
    

    This basically reproduces by hand precisely what the C++ const keyword would do automatically. In psuedo-C++ terms, a reference of type const Foo & is like an automatically generated type that only includes those members of Foo that were marked as const members. Translating this into some theoretical future version of C#, you'd declare FooClass like this:

    class FooClass
    {
        public void MutateMyStateYouBadBoy() { ... }
    
        public string Message
        {
            get const { ... }
            set { ... }
        }
    }
    

    Really all I've done is merged the information in IFooConst back into FooClass, by tagging the one safe member with a new const keyword. So in a way, adding a const keyword wouldn't add much to the language besides a formal approach to this pattern.

    Then if you had a const reference to a FooClass object:

    const FooClass f = GetMeAFooClass();
    

    You would only be able to call the const members on f.

    Note that if the FooClass definition is public, the caller could cast an IFooConst into a FooClass. But they can do that in C++ too - it's called "casting away const" and involves a special operator called const_cast<T>(const T &).

    There's also the issue of interfaces not being very easy to evolve between versions of your product. If a third party may implement an interface you define (which they are free to do if they can see it), then you can't add new methods to it in future versions without requiring others to recompile their code. But that's only a problem if you are writing an extensible library for others to build on. Maybe a built-in const feature would solve this problem.

    0 讨论(0)
  • 2020-12-28 20:42

    To clarify Jon Skeet's comment you can make a view, that is an immutable wrapper class for the mutable Foo. Here's an example:

    class Foo{
     public string A{get; set;}
     public string B{get; set;}
     //...
    }
    
    class ReadOnlyFoo{
      Foo foo; 
      public string A { get { return foo.A; }}
      public string B { get { return foo.B; }}
    }
    
    0 讨论(0)
提交回复
热议问题