C# public переменная как записываемая внутри класса, но только для чтения вне класса

У меня есть класс .Net C#, где мне нужно сделать переменную общедоступной. Мне нужно инициализировать эту переменную в методе (не в конструкторе). Однако, я не хочу, чтобы переменная была modifieable другими классами. Возможно ли это?

9 ответов


не используйте поле-используйте свойство:

class Foo
{
    public string Bar { get; private set; }
}

в этом примере Foo.Bar читается везде и записывается только членами .

в качестве примечания этот пример использует функцию C#, представленную в версии 3 под названием автоматически реализуемые свойства. Это синтаксический сахар, который компилятор преобразует в регулярное свойство, имеющее частное резервное поле, например:

class Foo
{
    [CompilerGenerated]
    private string <Bar>k__BackingField;

    public string Bar
    {
        [CompilerGenerated]
        get
        {
            return this.<Bar>k__BackingField;
        }
        [CompilerGenerated]
        private set
        {
            this.<Bar>k__BackingField = value;
        }
    }
}

public class Foo
{
  public string Bar { get; private set; } 
}

для этого необходимо использовать свойство. Если вы в порядке с автоматической реализацией getter / setter, это будет работать:

public string SomeProperty { get; private set; }

обратите внимание, что вы не должны предоставлять поля как общедоступные, за исключением некоторых ограниченных обстоятельств. Вместо этого используйте свойство.


конечно. Сделайте это свойством и сделайте сеттера частным:

public Int32 SomeVariable { get; private set; }

затем, чтобы установить его (изнутри некоторого метода в классе):

SomeVariable = 5;

используйте закрытую переменную и предоставьте общедоступное свойство.

class Person
{
  private string name;

  public string Name
  {
    get
    {
      return name;
    }
  }
}

вы не можете использовать свойство для этого? Если вы:

private string _variable
public string Variable {
    get {
        return _variable;
    }
}

Necro наверняка, но это оголяет упоминание с улучшениями языка в 6.0

class Foo {

    // The new assignment constructor is wonderful shorthand ensuring
    // that the var is only writable inside the obj's constructor
    public string Bar { get; } = String.Empty;

    }

ответы до сих пор работают хорошо, пока вы не используете ссылочные типы. В противном случае вы все равно сможете манипулировать внутренними элементами этой переменной. е.г:

using System;
namespace Playground
{
    class Program
    {
        static void Main(string[] args)
        {
            var fo = new Fo();
            fo.Init();
            Console.WriteLine(fo.SomeBar.SomeValue);
            fo.SomeBar.SomeValue = "Changed it!";
            Console.WriteLine(fo.SomeBar.SomeValue);
            Console.Read();
        }
        public class Fo
        {
            public Bar SomeBar { get; private set; }
            public void Init()
            {
                SomeBar = new Bar{SomeValue = "Hello World!"};
            }
        }
        public class Bar
        {
            public String SomeValue { get; set; }
        }
    }
}
Это приведет к выходу консоли :
Hello World!
Changed it!

что может быть именно то, что вы хотите, как вы не сможете поменять SomeBar но если вы хотите сделать внутренние части переменной неизменяемыми, вам нужно передать копию переменной, например:


using System;
namespace Playground
{
    class Program
    {
        static void Main(string[] args)
        {
            var fo = new Fo();
            fo.Init();
            Console.WriteLine(fo.SomeBar.SomeValue);
            fo.SomeBar.SomeValue = "Changed it!";
            Console.WriteLine(fo.SomeBar.SomeValue);
            Console.Read();
        }
        public class Fo
        {
            private Bar _someHiddenBar;
            public Bar SomeBar => new Bar(_someHiddenBar);
            public void Init()
            {
                _someHiddenBar = new Bar{SomeValue = "Hello World!"};
            }
        }
        public class Bar
        {
            public String SomeValue { get; set; }
            public Bar(){}
            public Bar(Bar previousBar)
            {
                SomeValue = previousBar.SomeValue;
            }
        }
    }
}
который будет результат:
Hello World!
Hello World!

см. комментарии, почему я добавил третий пример:


using System;
namespace Playground
{
    class Program
    {
        static void Main(string[] args)
        {
            var fo = new Fo();
            fo.Init();
            Console.WriteLine(fo.SomeBar.SomeValue);
            //compile error
            fo.SomeBar.SomeValue = "Changed it!";
            Console.WriteLine(fo.SomeBar.SomeValue);
            Console.Read();
        }
        public class Fo
        {
            private Bar _someHiddenBar;
            public Bar SomeBar => new Bar(_someHiddenBar);
            public void Init()
            {
                _someHiddenBar = new Bar("Hello World!");
            }
        }
        public class Bar
        {
            public String SomeValue { get; }
            public Bar(string someValue)
            {
                SomeValue = someValue;
            }
            public Bar(Bar previousBar)
            {
                SomeValue = previousBar.SomeValue;
            }
        }
    }
}

определить его как отдельный? Это то, что вы просите, вы можете изменить его в любом месте внутри класса контейнера, но вы не можете выйти из него