Подтвердить что ты не робот

Как установить поле readonly в метод initialize, который вызывается из конструктора?

Я уверен, что я где-то видел, что могу сделать следующее, используя атрибут выше моего метода Init(), который сообщает компилятору, что метод Init() должен быть вызван только из конструктора, что позволяет поле readonly. Я забыл, что называется атрибутом, и я не могу найти его в 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;
    }
}
4b9b3361

Ответ 1

Ответ Роба - это способ сделать это, в моей книге. Если вам нужно инициализировать несколько полей, вы можете сделать это с помощью параметров 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, но вы также хотите иметь возможность устанавливать их по-разному в производном классе (без необходимости связывать тонну параметров через некоторый конструктор protected). Но может быть, это только я.

Ответ 2

Нет, вы не можете. В принципе, вы должны выполнить инициализацию в конструкторе - что он там для.

Для повторного использования, если у вас есть несколько конструкторов, попробуйте сделать все, кроме одного, цепочкой, в "главный" конструктор, который выполняет всю реальную работу.

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

EDIT: я бы не включил отражение как реальный способ сделать это. Существуют всевозможные заявления, которые вы можете сделать, которые не включают злоупотребления посредством отражения. Хотите, чтобы строковый литерал "x" превратился в "y"? Конечно, вы можете сделать это с отражением, если у вас есть правильные разрешения... но вы абсолютно не должны.

Ответ 3

Вместо использования метода 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
    }
}

Это может быть немного поздно, чтобы добраться до нужного вам оригинального человека, но похоже, что это решительно решит проблему... Без необходимости использовать какие-либо неприятные отражения или параметры.

Ответ 4

Единственное решение, о котором я могу думать, - это вернуть значение из метода Init(), которому должно быть присвоено поле readonly:

public class Class
{
    private readonly int readonlyField;

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

    private int Init()
    {
        return 1;
    }
}

Ответ 5

Это невозможно. Поля, помеченные readonly, могут быть установлены только из конструктора

Ответ 6

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

  • Инициализировать поле в объявлении.
  • Инициализировать поле в конструкторе (вручную встраивать свой метод Init).
  • Присвоить поле значение, возвращаемое методом, например: _myField = GetInitialMyFieldValue();
  • Передайте поле методу 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);
 } 

Ответ 7

То, что я закончил в текущей технологии (С# 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);
    }
}

Не самый чистый, но мне кажется чище.

Ответ 8

Компилятор С# позволяет вам устанавливать только поля readonly, если вы инициализируете их inline:

private readonly int readonlyField = 1;

или от конструктора:

public Class()
{
    readonlyField = 1;
}

Ответ 9

Я думаю, что это работает, если использовать Reflection. На самом деле это работает для меня:

    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 является открытым, а не частным. Я знаю, что вы можете редактировать частное поле, но я не уверен, почему он не работает для меня!

Ответ 10

Как насчет инициализированного свойства только с геттером (начиная с С# 6.0)?

    private int MyProperty { get; } = 0;

Ответ 11

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

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