C# 在.NET中强键入属性名称

C# 在.NET中强键入属性名称,c#,.net,vb.net,strong-typing,C#,.net,Vb.net,Strong Typing,假设我有一个具有一个属性的类 Public Class MyClass Public Property MyItem() as Object .... End Property End Class 我必须将属性的名称传递给函数调用。(请不要问为什么要这样做,这是第三方框架)。比如说 SomeFunc("MyItem") 但我想做的是,将字符串更改为强类型参数。也就是说,如果属性名称被重命名或更改,它也应该反映在这里 所以这类的东西: Dim objectForStro

假设我有一个具有一个属性的类

Public Class MyClass
   Public Property MyItem() as Object
      ....
   End Property
End Class
我必须将属性的名称传递给函数调用。(请不要问为什么要这样做,这是第三方框架)。比如说

SomeFunc("MyItem")
但我想做的是,将字符串更改为强类型参数。也就是说,如果属性名称被重命名或更改,它也应该反映在这里

所以这类的东西:

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

我肯定这行不通。有没有一种方法可以做到这一点?(C#或VB.NET,任何东西都很酷)

您可以始终使用包含
string
常量的静态类,而不是传递
string
文本:

public static class ObjectForStrongTyping
{
    public const string MyItem = "MyItem";
    public const string MyOtherItem = "MyOtherItem";
    // ...
}
您的代码将变成:

SomeFunc(ObjectForStrongTyping.MyItem);

如果只有一个属性,则可以执行此操作-获取类的第一个属性的属性信息:

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

'VB syntax
GetType(MyClass).GetProperties()(0).Name
编辑结果是,在可以使用表达式的地方,也可以使用这种反射(C#代码)

公共静态类ObjectExtensions{
公共静态字符串GetVariableName(此T obj){
System.Reflection.PropertyInfo[]objGetTypeGetProperties=obj.GetType().GetProperties();
if(objGetTypeGetProperties.Length==1)
返回objGetTypeGetProperties[0]。名称;
其他的
抛出新ArgumentException(“对象必须包含一个属性”);
}
}
班级计划{
静态void Main(字符串[]参数){
WriteLine(Console.WriteLine(new{(new MyClass()).MyItem}.GetVariableName()););
}
}

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

这里是一个使用来自的类的解决方案


此解决方案在C#和VB.NET中都可以使用,但lambda函数的VB.NET语法不够清晰,这可能会降低此解决方案在VB中的吸引力。我的例子将用C#表示

您可以使用C#3的lambda函数和表达式树功能实现所需的效果。基本上,您将编写一个名为SomeFuncHelper的包装函数,并按如下方式调用它:

MyClass objForStrongTyping = new MyClass();
SomeFuncHelper(() => objForStrongTyping.MyItem);
SomeFuncHelper的实现如下所示:

void SomeFuncHelper(Expression<Func<object>> expression)
{
    string propertyName = /* get name by examining expression */;
    SomeFunc(propertyName);
}
您可能希望阅读表达式树并使用代码使其更健壮,但这是一般的想法


更新:这与Jason的解决方案类似,但允许helper函数调用中的lambda表达式稍微简单一些(
()=>obj.Property
,而不是
(SomeType obj)=>obj.Property
)。当然,只有当您已经有了该类型的实例时,这才更简单。

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

相信我,当您有很多调用时,反射和linq表达式会降低应用程序的性能

糟糕的是,T4在网络核心中消失了(

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

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

using System.Linq.Expressions;

namespace ConsoleApp1
{
    public static class Helper
    {
        public static string GetPropertyName<T>(Expression<Func<T, object>> 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<T>(this T obj, Expression<Func<T, object>> 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<SampleClass>(x => x.MyProperty));

            // Property name of instance
            var someObject = new SampleClass();
            Console.WriteLine(someObject.GetPropertyName(x => x.MyProperty));

            Console.ReadKey();
        }
    }
}
使用System.Linq.Expressions;
名称空间控制台EAPP1
{
公共静态类助手
{
公共静态字符串GetPropertyName(表达式propertyExpression)
{
var member=propertyExpression.Body作为MemberExpression;
如果(成员!=null)
返回member.member.Name;
其他的
抛出新ArgumentNullException(“未找到属性名”);
}
公共静态字符串GetPropertyName(此T对象,表达式propertyExpression)
{
返回GetPropertyName(propertyExpression);
}
}
公共类样本类
{
公共字符串MyProperty{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//类型的属性名称
WriteLine(Helper.GetPropertyName(x=>x.MyProperty));
//实例的属性名称
var someObject=new SampleClass();
WriteLine(someObject.GetPropertyName(x=>x.MyProperty));
Console.ReadKey();
}
}
}
性能结果(100万次呼叫):

StaticSampleClass.MyProperty
-8毫秒

nameof(SampleClass.MyProperty)
-8毫秒

Helper.GetPropertyName(x=>x.MyProperty)
-2000 ms

在C#6.0中,有一个新功能名为nameof。基本上,您可以这样做:

var name = nameof(MyClass.MyItem);
从C#到VB的Telerik代码转换器来看,这似乎是VB的等价物:

Dim name = nameof([MyClass].MyItem)
因此,您可以执行以下操作:

SomeFunc(nameof(MyClass.MyItem));
以下是对microsoft文档的参考:

+1:虽然它不像LINQ和typeof(…)那样“自动”解决方案,它超级简单,维护也非常简单。哎哟。现在我们不必担心属性更改名称,我们必须担心添加/重新排序属性?是的,它非常脏,但根据OP,类只有一个属性。有关更好的解决方案,请参阅编辑。使用编辑,这是一个非常有趣的答案。项目n方法很好。有没有建议使用哪种方法更有意义?在VB.Net中,匿名类型语法比lambda语法更简洁。很好,这可以包装成一个扩展吗?
public static class StaticSampleClass
{
    public const string MyProperty = "MyProperty";
}
using System.Linq.Expressions;

namespace ConsoleApp1
{
    public static class Helper
    {
        public static string GetPropertyName<T>(Expression<Func<T, object>> 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<T>(this T obj, Expression<Func<T, object>> 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<SampleClass>(x => x.MyProperty));

            // Property name of instance
            var someObject = new SampleClass();
            Console.WriteLine(someObject.GetPropertyName(x => x.MyProperty));

            Console.ReadKey();
        }
    }
}
var name = nameof(MyClass.MyItem);
Dim name = nameof([MyClass].MyItem)
SomeFunc(nameof(MyClass.MyItem));