c# - variable - ¿Cómo configuro un campo de solo lectura en un método de inicialización que se llama desde el constructor?
seal c# (8)
Estoy seguro de que he visto en alguna parte que puedo hacer lo siguiente al usar un atributo sobre mi método Init (), que le dice al compilador que el método Init () solo debe invocarse desde el constructor, permitiendo así que el campo readonly ser establecido Sin embargo, olvidé cómo se llama el atributo, y parece que no puedo encontrarlo en 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;
}
}
Creo que funciona si uso Reflection. En realidad, esto funciona para mí:
public class Class
{
private readonly int readonlyField;
public int MyField()
{
return readonlyField;
}
public Class()
{
readonlyField = 9;
}
}
y
static void Main(string[] args)
{
Class classObj = new Class();
Console.WriteLine(classObj.MyField());//9
Misc.SetVariableyByName(classObj, "readonlyField", 20);//20
Console.WriteLine(classObj.MyField());
}
esto es 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;
}
Lo único es que readonlyField es público, no privado. Sé que puedes editar un campo privado, pero no estoy seguro de por qué no funciona para mí.
El compilador de C # solo le permite establecer campos de solo lectura si los está inicializando en línea:
private readonly int readonlyField = 1;
o del constructor:
public Class()
{
readonlyField = 1;
}
En lugar de usar un método Initialize, qué tal heredar un constructor básico a través de todos sus otros constructores. es decir
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
}
}
Esto puede ser un poco tarde para llegar a la persona original que lo necesita, pero parece que solucionará el problema de manera limpia ... Sin la necesidad de usar ningún tipo de reflejo desagradable o parámetros de salida.
Esto no se puede hacer. Los campos que están etiquetados con readonly
solo se pueden configurar desde el constructor
Jared tiene razón; esto no es posible. Las soluciones que se me ocurren son:
- Inicializa el campo en la declaración.
- Inicialice el campo en el constructor (alinee manualmente su método
Init
). - Asigne el campo a un valor devuelto por un método, por ejemplo:
_myField = GetInitialMyFieldValue();
- Pase el campo al método
Init
, con el modificador deout
. Esto puede ser útil si tiene muchos campos para inicializar, que dependen de los parámetros del constructor. P.ej
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);
}
La única solución que puedo pensar es devolver el valor del método Init()
que el campo readonly
necesita asignarse:
public class Class
{
private readonly int readonlyField;
public Class()
{
readonlyField = Init();
}
private int Init()
{
return 1;
}
}
Lo que terminé haciendo en la tecnología actual (C # 7.x) es usar el sistema de valor tuple:
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);
}
}
Tampoco el más limpio, pero me parece más limpio.
La respuesta de Rob es la manera de hacerlo, en mi libro. Si necesita inicializar varios campos, puede hacerlo utilizando out
parámetros:
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;
}
}
Personalmente, encuentro que esto tiene sentido en ciertos escenarios, como cuando desea que sus campos sean de readonly
pero también desea poder configurarlos de manera diferente en una clase derivada (sin tener que encadenar una tonelada de parámetros a través de algún constructor protected
). Pero tal vez sea solo yo.