Константный объект С#

Рейтинг: 0Ответов: 1Опубликовано: 24.02.2023
void test(in A a) {
    a.modify(); // Не константный метод. Вызови ошибку! Нет...
}

A a = new A(1, 2);

test(a);
Console.WriteLine($"a.a: {a.a}");

public class A {
    public int a;
    public int b;

    public A(int a, int b) { this.a = a; this.b = b; } // можно красивее, но пока не умею )

    public void modify() => a = b;
}

Как мне защитить себя от вызова для константного объекта неконстантного метода?

Ответы

▲ 1

Средствами компилятора вы не можете изменяемый объект превратить в неизменяемый.

Но вы можете это сделать средствами ООП. Например, объявить интерфейс только для чтения

public interface IMyObjectReadonly
{
    int A{get;}
    int B{get;}
}

public class MyObject : IMyObjectReadonly
{
    public int A {get; private set;}
    public int B {get; private set;}
    
    public void SetA(int a) => A = a;
    public void SetB(int b) => B = b;
}

void Foo(IMyObjectReadonly ob)
{
    ob.SetA(10); // Error
}

Вы тут можете возразить, что вообще что никто не мешает ob кастануть в MyObject и вызвать что надо, типа ((MyObject)ob).SetA(10); - и, конечно, кто так делает, будет сам себе злобным буратиной. Но если и от этого надо защищаться, то можно написать враппер, например

public class MyObject
{
    public int A {get; private set;}
    public int B {get; private set;}
    
    public void SetA(int a) => A = a;
    public void SetB(int b) => B = b;
    
    public IMyObjectReadonly AsReadonly() => new MyObjectReadonlyWrapper(this);

    private class MyObjectReadonlyWrapper : IMyObjectReadonly
    {
        private MyObject inner;
        public MyObjectReadonlyWrapper(MyObject inner)
        {
            this.inner = inner;
        }
        
        public int A => inner.A;
        public int B => inner.B;
    }
}

И вызывать метод Foo как то так

var myOb = new MyObject();
Foo(myOb.AsReadonly());

В этом случае никакие касты никуда не помогут. Единственным вариантом достучаться до объекта будет рефлексия - а это уже не просто злобное буратинство, это уже стрельба по ногам :)