У меня есть класс .Net С#, где мне нужно сделать переменную общедоступной. Мне нужно инициализировать эту переменную в методе (не в конструкторе). Однако я не хочу, чтобы переменная могла быть изменена другими классами. Это возможно?
Публичная переменная С# как доступная для записи внутри класса, но только для чтения вне класса
Ответы (8)
Не используйте поле — используйте свойство:
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;
}
}
}
Add
, если список является членом. Мне пришлось иметь дело с этим со списком (конечно, это только один вариант использования ссылки), и в итоге я сделал член ReadOnlyCollection только с геттером и частной переменной - списком.
- person Do-do-new; 05.11.2018
Вы должны использовать свойство для этого. Если у вас все в порядке с автоматической реализацией геттера/сеттера, это будет работать:
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;
}
}
Пока ответы работают хорошо, если вы не используете ссылочные типы. В противном случае вы все равно сможете манипулировать внутренностями этой переменной. например:
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;
}
}
}
}
fo.SomeBar.SomeValue = "Changed it!";
, который не выполняет ни присваивания, ни исключения. Если бы это был настоящий код, его отладка была бы кошмаром. Вы должны сделать вещи неизменяемыми, чтобы вы даже не могли скомпилировать или, вы должны генерировать исключение.
- person rbm; 08.08.2017
private set;
- наиболее распространенный способ. В вашем примере фактически два класса, поэтому вам нужно будет контролировать Fo.Bar
и Bar.SomeValue
и сделать их неизменяемыми.
- person rbm; 08.08.2017
SomeValue
закрытым, то Fo
модификация, о которой просил MikeTWebb, не будет разрешена.
- person kkCosmo; 08.08.2017
Некро точно, но это стоит упомянуть с улучшениями языка в 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; private set; } = String.Empty;
}
Определить его как частный? Это то, о чем вы просите, вы можете изменить его в любом месте внутри класса контейнера, но вы не можете выйти за его пределы.