强在.NET中键入属性名称

假设我有一个属性有一个属性

Public Class MyClass Public Property MyItem() as Object .... End Property End Class 

我必须将属性的名称传递给函数调用。 (请不要问为什么应该这样做,它是第三方框架)。 例如

 SomeFunc("MyItem") 

但我想要做的是,将字符串更改为强类型参数。 这意味着,如果重命名或更改属性名称,也应该在此处反映出来。

所以这种类型的东西:

 Dim objectForStrongTyping as New MyClass() SomeFunc(objectForStrongTyping.MyItem().Name()) 

我相信这不会奏效。 有没有办法可以完成这种powershell打字? (C#或VB.NET,任何事情都很酷)

这是使用System.Linq.Expressions类的解决方案。

 static MemberInfo GetMemberInfo( Expression> expression ) { var member = expression.Body as MemberExpression; if (member != null) { return member.Member; } throw new ArgumentException("expression"); } 

把它扔到某个类( ExpressionHelper ?)。

用法:

 class SomeClass { public string SomeProperty { get; set; } } MemberInfo member = GetMemberInfo((SomeClass s) => s.SomeProperty); Console.WriteLine(member.Name); // prints "SomeProperty" on the console 

在C#6.0中有一个名为nameof的新function。 基本上你可以这样做:

 var name = nameof(MyClass.MyItem); 

查看从C#到VB的Telerik代码转换器,它似乎是VB的等价物:

 Dim name = nameof([MyClass].MyItem) 

所以你可以做到以下几点:

 SomeFunc(nameof(MyClass.MyItem)); 

以下是对microsoft文档的引用: https : //docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/keywords/nameof

这个解决方案适用于C#和VB.NET,但lambda函数的VB.NET语法并不干净,这可能会使这个解决方案在VB中缺乏吸引力。 我的例子将在C#中。

你可以使用C#3的lambda函数和表达式树特性来实现你想要的效果。基本上,你会编写一个名为SomeFuncHelper的包装器函数并像这样调用它:

 MyClass objForStrongTyping = new MyClass(); SomeFuncHelper(() => objForStrongTyping.MyItem); 

SomeFuncHelper实现如下:

 void SomeFuncHelper(Expression> expression) { string propertyName = /* get name by examining expression */; SomeFunc(propertyName); } 

lambda表达式() => objForStrongTyping.MyItem被转换为一个Expression对象,该对象被传递给SomeFuncHelper。 SomeFuncHelper检查Expression,拉出属性名称,并调用SomeFunc。 在我的快速测试中,以下代码用于检索属性名称,假设SomeFuncHelper总是如上所示调用(ie () => someObject.SomeProperty ):

 propertyName = ((MemberExpression) ((UnaryExpression) expression.Body).Operand).Member.Name; 

您可能希望阅读表达式树并使用代码使其更加健壮,但这是一般的想法。

更新:这类似于Jason的解决方案,但允许helper-function调用中的lambda表达式更简单( () => obj.Property而不是(SomeType obj) => obj.Property )。 当然,如果你已经有一个类型的实例,这只会更简单。

如果只有一个属性,你可以这样做 – 获取该类的第一个属性的属性信息:

 //C# syntax typeof(MyClass).GetProperties()[0].Name; 'VB syntax GetType(MyClass).GetProperties()(0).Name 

编辑结果,你可以使用表达式,你也可以使用投影这种reflection(C#代码)。

 public static class ObjectExtensions { public static string GetVariableName(this T obj) { System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties(); if(objGetTypeGetProperties.Length == 1) return objGetTypeGetProperties[0].Name; else throw new ArgumentException("object must contain one property"); } } class Program { static void Main(string[] args) { Console.WriteLine(Console.WriteLine(new { (new MyClass()).MyItem}.GetVariableName());); } } 

使用此解决方案,该类可以具有任意数量的属性,您可以获得其他任何名称。

您总是可以使用包含string常量的静态类,而不是传入string文字:

 public static class ObjectForStrongTyping { public const string MyItem = "MyItem"; public const string MyOtherItem = "MyOtherItem"; // ... } 

您的代码将变为:

 SomeFunc(ObjectForStrongTyping.MyItem); 

我认为最好的解决方案是使用T4生成静态常量(例如T4MVC )。

 public static class StaticSampleClass { public const string MyProperty = "MyProperty"; } 

相信我,当你有很多调用reflection和linq表达正在降低你的应用程序的性能。

不好的是T4在净核心中消失了。 🙁

C#6.0中的好东西你可以使用nameof(SampleClass.MyProperty)

在最坏的情况下,您可以使用以下示例:

 using System.Linq.Expressions; namespace ConsoleApp1 { public static class Helper { public static string GetPropertyName(Expression> propertyExpression) { var member = propertyExpression.Body as MemberExpression; if (member != null) return member.Member.Name; else throw new ArgumentNullException("Property name not found."); } public static string GetPropertyName(this T obj, Expression> propertyExpression) { return GetPropertyName(propertyExpression); } } public class SampleClass { public string MyProperty { get; set; } } class Program { static void Main(string[] args) { // Property name of type Console.WriteLine(Helper.GetPropertyName(x => x.MyProperty)); // Property name of instance var someObject = new SampleClass(); Console.WriteLine(someObject.GetPropertyName(x => x.MyProperty)); Console.ReadKey(); } } } 

表现结果(100万次通话):

StaticSampleClass.MyProperty – 8毫秒

nameof(SampleClass.MyProperty) – 8毫秒

Helper.GetPropertyName(x => x.MyProperty) – 2000毫秒