Как получить текущее имя свойства через отражение?
Я хотел бы получить имя свойства, когда я нахожусь в нем через механизм отражения. Возможно ли это?
Обновление:
У меня такой код:
public CarType Car
{
get { return (Wheel) this["Wheel"];}
set { this["Wheel"] = value; }
}
И поскольку мне нужно больше таких свойств, я хотел бы сделать что-то вроде этого:
public CarType Car
{
get { return (Wheel) this[GetThisPropertyName()];}
set { this[GetThisPropertyName()] = value; }
}
Ответы
Ответ 1
Так как свойства - это действительно просто методы, вы можете сделать это и очистить возвращаемый get_:
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Something;
Console.ReadLine();
}
public string Something
{
get
{
return MethodBase.GetCurrentMethod().Name;
}
}
}
Если вы определяете производительность, вы должны найти MethodBase.GetCurrentMethod() намного быстрее, чем StackFrame. В .NET 1.1 у вас также будут проблемы с StackFrame в режиме выпуска (из памяти, думаю, я нашел, что это было в 3 раза быстрее).
Я уверен, что проблема с производительностью не вызовет слишком много проблем, хотя интересная дискуссия о медленности стека может быть найдена здесь.
Я думаю, что другой вариант, если бы вы были обеспокоены производительностью, заключался бы в создании фрагмента кода Visual Studio Intellisense, который создает для вас свойство, а также создает строку, соответствующую имени свойства.
Ответ 2
Я хотел бы узнать больше о контексте, в котором он вам нужен, поскольку мне кажется, что вы уже должны знать, с каким свойством вы работаете в аксессуре свойств. Однако, если вы, вероятно, можете использовать MethodBase.GetCurrentMethod().Name и удалить что-либо после get_/set_
.
Обновление
Основываясь на ваших изменениях, я бы сказал, что вы должны использовать наследование, а не отражение. Я не знаю, какие данные содержатся в вашем словаре, но мне кажется, что вы действительно хотите иметь разные классы автомобилей, например, Sedan, Roadster, Buggy, StationWagon, не сохраняя тип в локальной переменной. Тогда у вас будут реализации методов, которые делают правильную вещь для этого типа автомобилей. Вместо того, чтобы узнать, какой у вас автомобиль, а затем что-то делаете, вы просто вызываете соответствующий метод, и объект Car делает правильную вещь, основываясь на том, что это за тип.
public interface ICar
{
void Drive( decimal velocity, Orientation orientation );
void Shift( int gear );
...
}
public abstract class Car : ICar
{
public virtual void Drive( decimal velocity, Orientation orientation )
{
...some default implementation...
}
public abstract void Shift( int gear );
...
}
public class AutomaticTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
public class ManualTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
Ответ 3
Вместо этого используйте MethodBase.GetCurrentMethod()!
Отражение используется для работы с типами, которые невозможно выполнить во время компиляции. Получение имени аксессура свойства, в котором вы находитесь, может быть определено во время компиляции, поэтому вы, вероятно, не должны использовать отражение для него.
Вы используете имя метода доступа из стека вызовов, используя System.Diagnostics.StackTrace
.
string GetPropertyName()
{
StackTrace callStackTrace = new StackTrace();
StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
string properyAccessorName = propertyFrame.GetMethod().Name;
return properyAccessorName.Replace("get_","").Replace("set_","");
}
Ответ 4
Немного запутанный пример, который вы представили, если только я его не получу.
С С# 6.0 вы можете использовать оператор nameof
.
public CarType MyProperty
{
get { return (CarType)this[nameof(MyProperty)]};
set { this[nameof(MyProperty)] = value]};
}
Если у вас есть метод, который все равно обрабатывает ваш getter/setter, вы можете использовать атрибут С# 4.5 CallerMemberName
, в этом случае вам даже не нужно повторять имя.
public CarType MyProperty
{
get { return Get<CarType>(); }
set { Set(value); }
}
public T Get<T>([CallerMemberName]string name = null)
{
return (T)this[name];
}
public void Set<T>(T value, [CallerMemberName]string name = null)
{
this[name] = value;
}
Ответ 5
FWIW Я реализовал такую систему:
[CrmAttribute("firstname")]
public string FirstName
{
get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
}
// this is in a base class, skipped that bit for clairty
public T GetPropValue<T>(string propName)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
return GetAttributeValue<T>(attributeName);
}
public void SetPropValue(string propName, object value)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
SetAttributeValue(attributeName, value);
}
private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
private string GetCrmAttributeName(string propertyName)
{
// keyName for our propertyName to (static) CrmAttributeName cache
string keyName = this.GetType().Name + propertyName;
// have we already done this mapping?
if (!PropToAttributeMap.ContainsKey(keyName))
{
Type t = this.GetType();
PropertyInfo info = t.GetProperty(propertyName);
if (info == null)
{
throw new Exception("Cannot find a propety called " + propertyName);
}
object[] attrs = info.GetCustomAttributes(false);
foreach (object o in attrs)
{
CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
if (attr != null)
{
// found it. Save the mapping for next time.
PropToAttributeMap[keyName] = attr.AttributeName;
return attr.AttributeName;
}
}
throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
}
// return the existing mapping
string result = PropToAttributeMap[keyName];
return result;
}
Также существует собственный класс атрибутов, называемый CrmAttributeAttribute.
Я настоятельно рекомендую против использовать GetStackFrame() как часть вашего решения, моя оригинальная версия решения изначально была намного опрятной:
return GetPropValue<string>();
Но это было на 600 раз медленнее, чем версия выше.
Ответ 6
Да, это!
string test = "test string";
Type type = test.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
string propName = pi.Name;
}
Ответ 7
Попробуйте использовать System.Diagnostics.StackTrace
, чтобы отразить стек вызовов. Свойство должно быть где-то в стеке вызовов (вероятно, сверху, если вы вызываете его непосредственно из кода свойства).
Ответ 8
Способ № 1
var a = nameof(SampleMethod); //a == SampleMethod
var b = nameof(SampleVariable); //b == SampleVariable
var c = nameof(SampleProperty); //c == SampleProperty
Способ № 2
MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property
Способ № 3
от StackTrace:
public static class Props
{
public static string CurrPropName =>
(new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");
public static string CurrMethodName =>
(new StackTrace()).GetFrame(1).GetMethod().Name;
}
вам просто нужно вызвать Props.CurrPropName
или Props.CurrMethodName
Способ № 4
Решение для .NET 4. 5+:
public static class Props
{
public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
return propertyName;
}
}
usgae: Props.GetCallerName();