Открытая переменная C # как доступная для записи внутри класса, но только для чтения вне класса - PullRequest
36 голосов
/ 11 января 2011

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

Ответы [ 9 ]

67 голосов
/ 11 января 2011

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

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

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

Какпримечание: в этом примере используется функция 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;
        }
    }
}
11 голосов
/ 11 января 2011
public class Foo
{
  public string Bar { get; private set; } 
}
6 голосов
/ 11 января 2011

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

public string SomeProperty { get; private set; }

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

4 голосов
/ 11 января 2011

Конечно.Сделайте это свойством, и сделайте установщик частным:

public Int32 SomeVariable { get; private set; }

Затем установите его (из какого-то метода в классе):

SomeVariable = 5;
3 голосов
/ 11 января 2011

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

class Person
{
  private string name;

  public string Name
  {
    get
    {
      return name;
    }
  }
}
2 голосов
/ 11 января 2011

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

private string _variable
public string Variable {
    get {
        return _variable;
    }
}
1 голос
/ 08 августа 2017

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

<code>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 , но если вы хотите сделать внутреннюю часть переменной не модифицируемой, вам необходимо вернуть копию переменной, например

<code>
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!

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

<code>
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;
            }
        }
    }
}
1 голос
/ 09 июня 2016

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;

    }
0 голосов
/ 11 января 2011

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

...