C# public variable as writeable inside the class but readonly outside the class

后端 未结 9 1688
说谎
说谎 2020-12-09 14:52

I have a .Net C# class where I need to make a variable public. I need to initialize this variable within a method (not within the constructor). However, I don\'t want the

相关标签:
9条回答
  • 2020-12-09 15:01

    The answers so far work good as long as you dont use reference types. Otherwise you will still be able to manipulate the internals of that variable. e.g:

    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; }
            }
        }
    }
    
    This will result in the console output:

    Hello World!
    Changed it!
    

    Which may be exactly what you want as you wont be able to change SomeBar but if you want to make the internals of the variable unmodifiable you need to pass back a copy of the variable, e.g.:

    
    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;
                }
            }
        }
    }
    
    which will result in the output:

    Hello World!
    Hello World!
    

    See comments for why I added the third example:

    
    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;
                }
            }
        }
    }
    

    0 讨论(0)
  • 2020-12-09 15:02
    public class Foo
    {
      public string Bar { get; private set; } 
    }
    
    0 讨论(0)
  • 2020-12-09 15:02

    You have to use a property for this. If you are fine with an automatic getter/setter implementation, this will work:

    public string SomeProperty { get; private set; }
    

    Note that you should not expose fields as public anyway, except in some limited circumstances. Use a property instead.

    0 讨论(0)
  • 2020-12-09 15:07

    Are you not allowed to use a property for this? If you are:

    private string _variable
    public string Variable {
        get {
            return _variable;
        }
    }
    
    0 讨论(0)
  • 2020-12-09 15:12

    Necro for sure, but this bares mentioning with the improvements to the language in 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;
    
        }
    
    0 讨论(0)
  • 2020-12-09 15:17

    Don't use a field - use a property:

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

    In this example Foo.Bar is readable everywhere and writable only by members of Foo itself.

    As a side note, this example is using a C# feature introduced in version 3 called automatically implemented properties. This is syntactical sugar that the compiler will transform into a regular property that has a private backing field like this:

    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;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题