我想通过反射机制获取属性名称。有可能吗?
更新: 我有这样的代码:
public CarType Car
{
get { return (Wheel) this["Wheel"];}
set { this["Wheel"] = value; }
}
因为我需要更多这样的属性,我想做这样的事情:
public CarType Car
{
get { return (Wheel) this[GetThisPropertyName()];}
set { this[GetThisPropertyName()] = value; }
}
答案 0 :(得分:51)
由于属性实际上只是方法,因此您可以执行此操作并清理返回的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倍)。
那就是说我确信性能问题不会引起太多问题 - 尽管有关StackFrame慢度的有趣讨论可能是found here。
如果您担心性能,我想另一个选择是创建一个Visual Studio Intellisense Code Snippet,为您创建属性,并创建一个与属性名称对应的字符串。
答案 1 :(得分:7)
我想知道更多关于你需要它的上下文,因为在我看来你应该已经知道你在属性访问器中使用了什么属性。但是,如果必须,您可以使用MethodBase.GetCurrentMethod()。在get_/set_
之后命名并删除任何内容。
<强>更新强>:
根据您的更改,我会说您应该使用继承而不是反射。我不知道你的词典里有什么数据,但在我看来你真的想拥有不同的Car类,比如Sedan,Roadster,Buggy,StationWagon,不要把类型保存在局部变量中。然后你会有方法的实现,为那种类型的汽车做正确的事情。然后你可以简单地调用适当的方法而不是找出你拥有的汽车类型,然后根据它的类型来调用适当的方法。
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...
}
}
答案 2 :(得分:5)
改为使用MethodBase.GetCurrentMethod()
Reflection用于处理在编译时无法完成的类型。获取您所在的属性访问者的名称可以在编译时决定,因此您可能不应该使用反射。
您可以使用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_","");
}
答案 3 :(得分:5)
你提出的一个有点混乱的例子,除非我没有得到它。
从C#6.0开始,您可以使用nameof
运算符。
public CarType MyProperty
{
get { return (CarType)this[nameof(MyProperty)]};
set { this[nameof(MyProperty)] = value]};
}
如果你有一个方法可以处理你的getter / setter,你可以使用C#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;
}
答案 4 :(得分:3)
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倍。
答案 5 :(得分:0)
是的,它是!
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;
}
答案 6 :(得分:0)
尝试使用System.Diagnostics.StackTrace
来反映调用堆栈。该属性应该位于调用堆栈中的某个位置(如果您直接从属性的代码中调用它,可能位于顶部)。
答案 7 :(得分:0)
var a = nameof(SampleMethod); //a == SampleMethod
var b = nameof(SampleVariable); //b == SampleVariable
var c = nameof(SampleProperty); //c == SampleProperty
MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property
来自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
.NET 4.5+的解决方案:
public static class Props
{
public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
return propertyName;
}
}
usgae:Props.GetCallerName();