强在.NET中键入属性名称

时间:2009-12-31 06:07:59

标签: c# .net vb.net strong-typing

说我有一个有一个属性的类

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,任何事情都很酷)

6 个答案:

答案 0 :(得分:21)

以下是使用System.Linq.Expressions中的类的解决方案。

static MemberInfo GetMemberInfo<TObject, TProperty>(
    Expression<Func<TObject, TProperty>> 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

答案 1 :(得分:5)

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

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

答案 2 :(得分:3)

这个解决方案适用于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);
}

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

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

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

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

答案 3 :(得分:1)

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

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

'VB syntax
GetType(MyClass).GetProperties()(0).Name

编辑事实证明,在可以使用表达式的地方,您还可以使用projection进行此类反射(C#代码)。

public static class ObjectExtensions {
    public static string GetVariableName<T>(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()););
    }
}

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

答案 4 :(得分:0)

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

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

您的代码将成为:

SomeFunc(ObjectForStrongTyping.MyItem);

答案 5 :(得分:0)

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

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

当你有很多调用反射时,请相信我,而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();
        }
    }
}

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

StaticSampleClass.MyProperty - 8毫秒

nameof(SampleClass.MyProperty) - 8毫秒

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