下面的课程包含字段城市。
我需要在类声明中输入时动态确定字段的名称 即我需要从对象城市的实例中获取字符串“city”。
我试过通过检查其在DoSomething()中的类型来尝试这样做,但在检查调试器中的Type内容时找不到它。
有可能吗?
public class Person
{
public string city = "New York";
public Person()
{
}
public void DoSomething()
{
Type t = city.GetType();
string field_name = t.SomeUnkownFunction();
//would return the string "city" if it existed!
}
}
下面的答案中有些人问我为什么要这样做。 这就是原因。
在我的真实世界中,城市上方有一个自定义属性。
[MyCustomAttribute("param1", "param2", etc)]
public string city = "New York";
我在其他代码中需要此属性。 要获取属性,我使用反射。 在反射代码中,我需要输入字符串“city”
MyCustomAttribute attr;
Type t = typeof(Person);
foreach (FieldInfo field in t.GetFields())
{
if (field.Name == "city")
{
//do stuff when we find the field that has the attribute we need
}
}
现在这不是类型安全的。 如果我在Person中的字段声明中将变量“city”更改为“workCity”,则除非我知道更新字符串,否则此行将失败
if (field.Name == "workCity")
//I have to make this change in another file for this to still work, yuk!
{
}
所以我试图找到一些方法将字符串传递给这段代码而不用实际输入。
是的,我可以将它声明为Person中的字符串常量(或类似的东西),但仍然会输入两次。
唷!这很难解释!!
感谢
感谢所有回答*的人*。它让我走上了一条新的道路来更好地理解lambda表达式。它创造了一个新问题。
答案 0 :(得分:49)
也许你需要这个。工作正常。
我发现了here。
static void Main(string[] args)
{
var domain = "matrix";
Check(() => domain);
Console.ReadLine();
}
static void Check<T>(Expression<Func<T>> expr)
{
var body = ((MemberExpression)expr.Body);
Console.WriteLine("Name is: {0}", body.Member.Name);
Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value));
}
输出将是:
Name is: 'domain' Value is: 'matrix'
答案 1 :(得分:37)
我知道这是一个老问题,但我试图达到同样的目的,谷歌把我送到了这里。几个小时后,我终于找到了办法。我希望其他人会觉得这很有用。
实际上有更多方法可以实现这一目标:
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
GetName3(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
static string GetName3<T>(Func<T> expr)
{
return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name;
}
第一个是最快的。最后2个比第1个慢约20倍。
http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
答案 2 :(得分:7)
city
是string
类型的实例。当您致电.GetType()
时,您将返回实际的字符串类型,该类型根本不知道您所在城市实例。
我很难理解为什么你不能在代码中输入“city”作为字符串文字,如果这就是你需要的。如果您分享了想要使用此值的内容以及在什么情况下您将调用DoSomething()
函数,这可能会有所帮助。
目前,我最好的猜测是你真正想做的是反映整个Person
类,以获得该类中的字段列表:
public void DoSomething()
{
MemberInfo[] members = this.GetType().GetMembers();
// now you can do whatever you want with each of the members,
// including checking their .Name properties.
}
好的,根据你的编辑,我还有更多的东西给你。
您可以在运行时找到使用属性修饰的字段名称,如下所示:
Type t = typeof(Person);
foreach (MemberInfo member in t.GetMembers()
.Where(m =>
m.GetCustomAttributes(typeof(MyCustomAttribute)).Any() ) )
{
// "member" is a MemberInfo object for a Peson member that is
// decorated with your attribute
}
如果需要,您还可以在第一个GetMembers()调用中使用绑定标志将其限制为仅字段。
答案 3 :(得分:4)
你提到“即我需要从对象城市的一个实例中获取字符串”city“。” 您是否希望从字段的值中获取字段名称。 例如:如果有2个人对象一个城市“纽约”而另一个城市“伦敦”,你是否正在寻找返回“城市”的功能。这是你的意思吗?
使用当前设计,您始终需要将FieldInfo中字段的名称与字符串进行比较。 如果您改为将其解耦,以便在反射过程中将标识符用作比较目的,作为属性的一部分,该怎么办? 像这样:
public enum ReflectionFields
{
CITY = 0,
STATE,
ZIP,
COUNTRY
}
[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
public class CustomFieldAttr : Attribute
{
public ReflectionFields Field { get; private set; }
public string MiscInfo { get; private set; }
public CustomFieldAttr(ReflectionFields field, string miscInfo)
{
Field = field;
MiscInfo = miscInfo;
}
}
public class Person
{
[CustomFieldAttr(ReflectionFields.CITY, "This is the primary city")]
public string _city = "New York";
public Person()
{
}
public Person(string city)
{
_city = city;
}
}
public static class AttributeReader<T> where T:class
{
public static void Read(T t)
{
//get all fields which have the "CustomFieldAttribute applied to it"
var fields = t.GetType().GetFields().Where(f => f.GetCustomAttributes(typeof(CustomFieldAttr), true).Length == 1);
foreach (var field in fields)
{
var attr = field.GetCustomAttributes(typeof(CustomFieldAttr), true).First() as CustomFieldAttr;
if (attr.Field == ReflectionFields.CITY)
{
//You have the field and you know its the City,do whatever processing you need.
Console.WriteLine(field.Name);
}
}
}
}
public class Program
{
public static void Main(string[] args)
{
PPerson p1 = new PPerson("NewYork");
PPerson p2 = new PPerson("London");
AttributeReader<PPerson>.Read(p1);
AttributeReader<PPerson>.Read(p2);
}
}
您现在可以自由地将Person的_city字段重命名为其他内容,并且您的调用代码仍然有效,因为使用反射的代码尝试使用ReflectionFields枚举值设置字段作为字段上属性集的初始化的一部分
答案 4 :(得分:4)
是的可能!!!
试试这个......
public string DoSomething(object city)
{
return city.GetType().GetProperty("Name",typeof(string)).GetValue(city,null);
}
答案 5 :(得分:1)
这里有两件事。
第一,正如上面所指出的那样,你得到的是字符串的类型,而不是Person。所以typeof(Person).GetMembers()会为你提供成员列表。
第二,更重要的是,看起来你误解了属性的目的。通常,属性用于标记成员以进行特定处理或添加其他信息。在这里,您使用名称来指示您想要的处理,以及用于指定参数的属性,即隐喻的混合或其他内容。
Abhijeet的答案更合适,你将该字段标记为 a 城市字段,然后用它做你喜欢的事情。我不同意的是我会使用不同的属性类,而不是枚举。
类似的东西:
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Field)]
public class MyCityAttribute : MyAttribute
{
}
[AttributeUsage(AttributeTargets.Field]
public class MyNameAttribute: MyAttribute
{
}
public class Person
{
[MyCity]
public string city = "New York";
[MyCity]
public string workCity = "Chicago";
[MyName]
public string fullName = "John Doe";
public Person()
{
}
public void DoSomething()
{
Type t = typeof(Person);
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var field in fields)
{
MyAttribute[] attributes = field.GetCustomAttributes(typeof(MyAttribute));
if (attributes.Count > 0)
{
if (attributes[0] is MyCityAttribute)
{
//Dosomething for city
break;
}
if (attributes[0] is MyNameAttribute)
{
//Dosomething for names
break;
}
}
}
}
}
这将允许您使用MyCity与MyName的不同参数,这些参数在处理每个参数时更有意义。
我认为你上面的'yuk'评论,你的头上钉了一针。如果重命名变量,则必须更改字符串常量,这表明您做错了。
答案 6 :(得分:0)
t.GetField("city", BindingFlags.Public | BindingFlags.Instance);
或者您可以调用GetFields()来获取所有字段
答案 7 :(得分:0)
您需要在类Person上调用get类型。迭代类的字段,如下面的答案
答案 8 :(得分:0)
这是不可能的(我认为它实际上是偶然的几个黑客并使用lambdas)。如果您想存储有关Person
的属性并且能够轻松获取属性的名称,建议您使用Dictionary<TKey, TValue>
命名空间中的System.Collections.Generic
。
您可以随时创建包含字典的公共属性。
public class Person
{
Dictionary<string, string> attributes = new Dictionary<string, string();
public string City
{
get { return attributes["city"]; }
set { attributes["city"] = value; }
}
public Person()
{
City = "New York";
}
}
您可以使用attributes.Keys
获取所有属性的列表。
答案 9 :(得分:0)
看一下这篇文章,因为它看起来与你想要做的相似:
Finding the variable name passed to a function
(尤其是Konrad Rudolph的回答)另一种方法可能是将“city”添加为属性中的一个参数,然后将鱼添加出去。
答案 10 :(得分:0)
您已经遍历FieldInfo
个对象的集合。在这些上查找您的属性,当您找到包含您的属性的FieldInfo
时,您就拥有了所需的属性。然后拨打.Name
就可以了。