public static class Class1
{
public static string name1 = "name1";
public static string name2 = this.Name;
}
К name2 автоматически присвоить значение его же имени, без указания имени в строке.
А можно как-то покороче чем это, без указания второй раз имени name2?:
public static string name2 = nameof(name2);
Решение для .NET 4.5+ / .NET Core
using System.Runtime.CompilerServices;
public static class MyName
{
public static string Get([CallerMemberName] string s = "") { return s; }
}
public class Class1
{
public static string name1 = "name1";
public static string name2 = MyName.Get();
}
Примечание. Тот факт, что при использовании в инициализаторе поля CallerMemberName возвращает имя этого поля (а не имя конструктора, который на самом деле является caller'ом), не документирован. Но это работает.
Решение для более старых версий .NET
using System;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
public static class MyName
{
static OpCode FindOpCode(short val)
{
OpCode ret = OpCodes.Nop;
FieldInfo[] mas = typeof(OpCodes).GetFields();
for (int i = 0; i < mas.Length; i++)
{
if (mas[i].FieldType == typeof(OpCode))
{
OpCode opcode = (OpCode)mas[i].GetValue(null);
if (opcode.Value == val)
{
ret = opcode;
break;
}
}
}
return ret;
}
static string GetFieldNameFromOffset(MethodBase mi, int offset)
{
MethodBody mb = null;
string result = "";
//получаем тело метода
mb = mi.GetMethodBody();
if (mb == null) throw new ApplicationException("Fatal error: GetMethodBody failed!");
//получаем IL-код
var msil = mb.GetILAsByteArray();
//получаем модуль, в котором расположен метод
var module = mi.Module;
short op;
int n = offset;
//парсим IL-код...
while (true)
{
if (n >= msil.Length) break;
//получаем код операции
if (msil[n] == 0xfe)
op = (short)(msil[n + 1] | 0xfe00);
else
op = (short)(msil[n]);
//найдем имя операции
OpCode opcode = FindOpCode(op);
string str = opcode.Name;
int size = 0;
//найдем размер операции
switch (opcode.OperandType)
{
case OperandType.InlineBrTarget: size = 4; break;
case OperandType.InlineField: size = 4; break;
case OperandType.InlineMethod: size = 4; break;
case OperandType.InlineSig: size = 4; break;
case OperandType.InlineTok: size = 4; break;
case OperandType.InlineType: size = 4; break;
case OperandType.InlineI: size = 4; break;
case OperandType.InlineI8: size = 8; break;
case OperandType.InlineNone: size = 0; break;
case OperandType.InlineR: size = 8; break;
case OperandType.InlineString: size = 4; break;
case OperandType.InlineSwitch: size = 4; break;
case OperandType.InlineVar: size = 2; break;
case OperandType.ShortInlineBrTarget: size = 1; break;
case OperandType.ShortInlineI: size = 1; break;
case OperandType.ShortInlineR: size = 4; break;
case OperandType.ShortInlineVar: size = 1; break;
default:
throw new Exception("Unknown operand type.");
}
size += opcode.Size;
int token = 0;
if (n > offset && (str == "stsfld" || str == "stfld"))
{
//найдем токен метаданных поля
token = (((msil[n + 1] | (msil[n + 2] << 8)) |
(msil[n + 3] << 0x10)) | (msil[n + 4] << 0x18));
//найдем поле в модуле по токену
var fi = module.ResolveField(token);
result = fi.Name;
return result;
}
n += size; //пропускаем нужное число байтов
}
return result;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static string Get()
{
//найдем вызывающий метод
var stack = new StackTrace(true);
var frame = stack.GetFrame(1);
var method = frame.GetMethod();
//найдем имя поля по смещению в IL
var name = GetFieldNameFromOffset(method, frame.GetILOffset());
return name;
}
}
public class Class1
{
public static string name1 = "name1";
public static string name2 = MyName.Get();
}
Для инициализатора поля name2 в коде конструктора компилятор генерирует последовательность IL-инструкций call и stsfld. Метод StackFrame.GetILOffset позволяет нам получить смещение инструкции call в байтах относительно начала кода конструктора, а MethodInfo.GetMethodBody позволяет получить сам IL-код конструктора. Чтобы получить FieldInfo, достаточно найти инструкцию, следующую за call, вытащить токен метаданных поля и передать его в метод Module.ResolveField. Из FieldInfo уже легко получить имя поля.
Давай представим себе ситуацию:
Cat Tomas = new Cat();
Cat Daryl = Tomas;
в даном случае и Tomas
и Daryl
переменные ссылаются на один и тот же обьект.
Какое значение должно вернутся если мы обратимся к Tomas.Name
и какое если мы обратимся к Daryl.Name
? Как в теории язык должен определить от какого имени был сделан вызов метода который возвращает имя?
Мое предположение в даном случае что можно сделать инициализацию имени переменной обязательной. Вроде
Cat Tomas = new Cat("Tomas");
Это не решает проблемы, зато работает в части случаев. (в примере выше, конечно же, работать не будет).
...........
Чисто в теории можно что-то придумать с стектрейсом. Но не факт что это будет работать в релизном билде.
...........
Чисто в теории возможно что-то придумать с рефлексией. Но не факт что это будет работать всегда как нужно и не выдавать ложных результатов, как в примере выше.
Вообще я настоятельно не советую так делать вообще в принципе. Используй nameof()
в местах где тебе это нужно. Это гарантированно не принесет проблем.
А так же, скорее всего, ты движешся в неправильном направлении и придумал неправильное решение своей задачи.
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
У меня есть 3 textbox(c внесенными данными),1 картинка которая загружается пользователем,1 Listbox в котором нужно выбрать вариант ответаКак и куда...
Уже перепробовал куча вариантовМне по сети приходят байты WaveIn с голосом и передаются в эту функцию: