如何在从构造函数调用的初始化方法中设置只读字段?

发布于 2024-09-19 22:47:34 字数 419 浏览 7 评论 0原文

我确信我在某个地方看到过,我可以通过使用 Init() 方法上方的属性来执行以下操作,该属性告诉编译器只能从构造函数中调用 Init() 方法,从而允许只读字段被设置。我忘记了这个属性叫什么,我似乎无法在谷歌上找到它。

public class Class
{
    private readonly int readonlyField;

    public Class()
    {
        Init();
    }

    // Attribute here that tells the compiler that this method must be called only from a constructor
    private void Init()
    {
        readonlyField = 1;
    }
}

I'm sure I've seen somewhere that I can do the following by using an attribute above my Init() method, that tells the compiler that the Init() method must only be called from the constructor, thus allowing the readonly field to be set. I forgot what the attribute is called though, and I can't seem to find it on google.

public class Class
{
    private readonly int readonlyField;

    public Class()
    {
        Init();
    }

    // Attribute here that tells the compiler that this method must be called only from a constructor
    private void Init()
    {
        readonlyField = 1;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

贪了杯 2024-09-26 22:47:34

罗伯的回答就是我书中的方法。如果您需要初始化多个字段,可以使用 out 参数来完成:

public class Class
{
    private readonly int readonlyField1;
    private readonly int readonlyField2;

    public Class()
    {
        Init(out readonlyField1, out readonlyField2);
    }

    protected virtual void Init(out int field1, out int field2)
    {
        field1 = 1;
        field2 = 2;
    }
}

我个人认为这在某些情况下是有意义的,例如当您希望字段为 readonly 但您希望能够在派生类中以不同方式设置它们(无需通过某些受保护的构造函数链接大量参数)。但也许这只是我。

Rob's answer is the way to do it, in my book. If you need to initialize multiple fields you can do it using out parameters:

public class Class
{
    private readonly int readonlyField1;
    private readonly int readonlyField2;

    public Class()
    {
        Init(out readonlyField1, out readonlyField2);
    }

    protected virtual void Init(out int field1, out int field2)
    {
        field1 = 1;
        field2 = 2;
    }
}

Personally I find this makes sense in certain scenarios, such as when you want your fields to be readonly but you also want to be able to set them differently in a derived class (without having to chain a ton of parameters through some protected constructor). But maybe that's just me.

英雄似剑 2024-09-26 22:47:34

我能想到的唯一解决方案是从 Init() 方法返回需要分配 readonly 字段的值:

public class Class
{
    private readonly int readonlyField;

    public Class()
    {
        readonlyField = Init();
    }

    private int Init()
    {
        return 1;
    }
}

The only solution I can think of is to return the value from the Init() method that the readonly field needs to be assigned:

public class Class
{
    private readonly int readonlyField;

    public Class()
    {
        readonlyField = Init();
    }

    private int Init()
    {
        return 1;
    }
}
好久不见√ 2024-09-26 22:47:34

不使用 Initialize 方法,而是通过所有其他构造函数继承基本构造函数如何?

public class MyClass
{
    readonly int field1;
    readonly double field2;
    public MyClass(int field1, double field2)
    {
        //put whatever initialization logic you need here...
        field1 = 10;
        field2 = 30.2;
    }
    public MyClass(int field1, double field2p1, double field2p2)
        : this(field1, (field2p1 + field2p2))
    {
        //put anything extra in here
    }
}

这可能有点晚了到达原来需要的人,但看起来这将彻底解决问题......而不需要使用任何类型的令人讨厌的反射或输出参数。

Instead of using an Initialize method, how about inheriting a basic constructor through all your other constructors.
i.e.

public class MyClass
{
    readonly int field1;
    readonly double field2;
    public MyClass(int field1, double field2)
    {
        //put whatever initialization logic you need here...
        field1 = 10;
        field2 = 30.2;
    }
    public MyClass(int field1, double field2p1, double field2p2)
        : this(field1, (field2p1 + field2p2))
    {
        //put anything extra in here
    }
}

This may be a little late to reach the original person in need, but it seems like this will cleanly solve the problem... Without the need to use any sort of nasty reflection or out parameters.

三月梨花 2024-09-26 22:47:34

贾里德是对的;这是不可能的。我能想到的解决方法是:

  1. 初始化声明中的字段。
  2. 在构造函数中初始化字段(手动内联您的 Init 方法)。
  3. 将字段分配给方法返回的值,例如:_myField = GetInitialMyFieldValue();
  4. 将字段传递给 Init 方法,使用 out 修改器。如果您有许多字段需要初始化(这些字段依赖于构造函数参数),这可能会很有用。例如

 private readonly int _x;
 private readonly string _y;

 private void Init(int someConstructorParam, out int x, out string y){ .. }

 public Class(int someConstructorParam)
 {
     Init(someConstructorParam, out _x, out _y);
 } 

Jared is right; this is not possible. The workarounds I can think of are:

  1. Initialize the field in the declaration.
  2. Initialize the field in the constructor (Manually inline your Init method).
  3. Assign the field to a value returned by a method, e.g.: _myField = GetInitialMyFieldValue();
  4. Pass the field to the Init method, with the out modifier. This may be useful if you have many fields to initialize, which are dependent on constructor parameters. E.g.

 private readonly int _x;
 private readonly string _y;

 private void Init(int someConstructorParam, out int x, out string y){ .. }

 public Class(int someConstructorParam)
 {
     Init(someConstructorParam, out _x, out _y);
 } 
暖树树初阳… 2024-09-26 22:47:34

这是不可能的。标记有 readonly 的字段只能从构造函数中设置

This cannot be done. Fields which are tagged with readonly can only be set from the constructor

ま柒月 2024-09-26 22:47:34

我最终在当前技术(C# 7.x)中所做的是使用值元组系统:

public class MyClass
{
    private readonly int x;
    private readonly int y;
    private readonly int z;

    public MyClass(int x)
    {
        this.x = x;
        (y, z) = InitYandZ();
    }

    private (int, int) InitYandZ()
    {
        return (5, 10);
    }
}

也不是最干净的,但对我来说似乎更干净。

What i ended up doing in current tech (C# 7.x) is use the value tuple system:

public class MyClass
{
    private readonly int x;
    private readonly int y;
    private readonly int z;

    public MyClass(int x)
    {
        this.x = x;
        (y, z) = InitYandZ();
    }

    private (int, int) InitYandZ()
    {
        return (5, 10);
    }
}

Not the cleanest either, But seems cleaner to me.

我的痛♀有谁懂 2024-09-26 22:47:34

C# 编译器仅允许您设置只读字段(如果您在内联初始化它们):

private readonly int readonlyField = 1;

或从构造函数初始化它们:

public Class()
{
    readonlyField = 1;
}

C# compiler only allows you to set readonly fields if you're initializing them inline:

private readonly int readonlyField = 1;

or from the constructor:

public Class()
{
    readonlyField = 1;
}
放赐 2024-09-26 22:47:34

仅使用 getter 的初始化属性怎么样(从 C# 6.0 开始)?

    private int MyProperty { get; } = 0;

How about an initialized property with a getter only (as of C# 6.0)?

    private int MyProperty { get; } = 0;
苹果你个爱泡泡 2024-09-26 22:47:34

我知道这已经晚了,但是如果需要初始化多个字段,那么使用类作为返回值而不是使用 out params 怎么样,有什么缺点吗?恕我直言,这比使用嵌套构造函数更方便、更具可读性。

public class MyInitClass
{
    public int Field1 { get; set; }
    public int Field2 { get; set; }
}

public class Class
{
    private readonly int readonlyField1;
    private readonly int readonlyField2;

    public Class()
    {
        var init = Init();
        readonlyField1 = init.Field1;
        readonlyField2 = init.Field2;
    }

    private MyInitClass Init()
    {
        return new MyInitClass() { Field1 = 1, Field2 = 2 };
    }
}

I know this is late, but what about using a class as a return value instead of using out params if there is a need to initialize multiple fields, are there any drawacks? Imho this is more convenient and more readable than using nested constructors.

public class MyInitClass
{
    public int Field1 { get; set; }
    public int Field2 { get; set; }
}

public class Class
{
    private readonly int readonlyField1;
    private readonly int readonlyField2;

    public Class()
    {
        var init = Init();
        readonlyField1 = init.Field1;
        readonlyField2 = init.Field2;
    }

    private MyInitClass Init()
    {
        return new MyInitClass() { Field1 = 1, Field2 = 2 };
    }
}
折戟 2024-09-26 22:47:34

我认为如果使用反射就可以了。实际上这对我有用:

    public class Class
        {
            private readonly int readonlyField;
        public int MyField()
        {
             return readonlyField;
        }
        public Class()
        {
            readonlyField = 9;
        }
    }

static void Main(string[] args)
        {

            Class classObj = new Class();
            Console.WriteLine(classObj.MyField());//9

            Misc.SetVariableyByName(classObj, "readonlyField", 20);//20
            Console.WriteLine(classObj.MyField());
         }

是 SetVariableByName():

public static b

ool SetVariableyByName(object obj, string var_name, object value)
            {
                FieldInfo info = obj.GetType().GetField(var_name, BindingFlags.NonPublic| BindingFlags.Instance);
                if (info == null)
                return false;
            /* ELSE */
            info.SetValue(obj, value);
            return true;          
        }

唯一的事情是 readonlyField 是公共的而不是私有的。我知道您可以编辑私有字段,但不确定为什么它对我不起作用!

I think it works if use Reflection. Actually this works for me:

    public class Class
        {
            private readonly int readonlyField;
        public int MyField()
        {
             return readonlyField;
        }
        public Class()
        {
            readonlyField = 9;
        }
    }

and

static void Main(string[] args)
        {

            Class classObj = new Class();
            Console.WriteLine(classObj.MyField());//9

            Misc.SetVariableyByName(classObj, "readonlyField", 20);//20
            Console.WriteLine(classObj.MyField());
         }

this is SetVariableByName():

public static b

ool SetVariableyByName(object obj, string var_name, object value)
            {
                FieldInfo info = obj.GetType().GetField(var_name, BindingFlags.NonPublic| BindingFlags.Instance);
                if (info == null)
                return false;
            /* ELSE */
            info.SetValue(obj, value);
            return true;          
        }

the only thing is that readonlyField is public not private. I know that you can edit a private field, but am not sure why its not working for me!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文