访问类成员的类型安全枚举

4

我的类MyClass<t>有以下方法

private static bool TypeHasProperty(string NameOfPropertyToMatch)
{
    var properties = typeof(t).GetProperties();
    var requiredProperty = properties.First(
            a => a.Name == NameOfPropertyToMatch);
    if (requiredProperty == null)
    {
        return false
    };

    return true;
}

在静态方法开始时调用:

MyClass<t>.SendToJavaScript(t InstanceOfType, string NameOfPropertyWithinType)

这是为了确保在继续之前,InstanceOfType实际上有该名称的属性,否则异常将不会被抛出直到很长一段时间(这些信息最终将被序列化并发送到 JavaScript 应用程序,需要知道要访问哪个属性才能完成任务)。

我想要一种好的、类型安全的方式来调用该方法,如果将来我决定更改属性的名称,它不会导致验证失败。

例如,我不想这样调用它:

MyClass<Person>.SendToJavaScript(MyPerson, "Name")

如果我决定在Person类中将Name更改为LastName,那么我需要确保回来更改这个魔法字符串。

我想要的是这样的:

MeClass<Person>.SendToJavaScript(
    MyPerson,
    TypeOf(Person).Properties.Name.ToString())

所以,如果我使用重构将Name更改为LastName,IDE将扫描该处并同时更改我的调用。是否存在类似的工具?或者我只需要在重构时小心一些?(我喜欢使用)
2个回答

5

我们在我们的代码中使用类似这样的东西:

private static bool TypeHasProperty<P>(Expression<Func<T, P>> accessor)
{
    var propertyName = ((MemberExpression)accessor.Body).Member.Name;
    var properties = typeof(T).GetProperties();
    return properties.Any(a => a.Name == propertyName);
}

使用它:

class Foo
{
    public int Baz { get; set; }
}

MyClass<Foo>.TypeHasProperty(f => f.Baz);

编辑:更改查询使用Any(),因为它更好地表达了您实际想要做的事情(给定名称的属性是否存在?)

请注意,如果找不到匹配项,First()将抛出异常。


看起来比我的回答好多了,我太着急停下来思考了 ;) - BartoszKP
这太棒了。我需要了解的超级简短答案是:表达式。它们是获得对象成员类型安全访问的最佳方式。尽管如此,我相信我的实现将看起来非常类似于这个。 - JHixson
像这样的调用,甚至需要验证 T 是否实际拥有成员 P 吗?似乎不可能以合法的方式调用 TypeHasProperty 使其失败。 - JHixson
@JHixson:这可能是一个字段而不是属性,如果是这样,您仍然可以进行调用,但验证将失败。 - ChrisWue

4

试试这个:

MeClass<Person>.SendToJavaScript(MyPerson, x => x.Name);

然后:

private static bool TypeHasProperty(Expression propertyExpression)
{
    var expression = GetMemberInfo(propertyExpression);
    string name = expression.Member.Name;

    return typeof(t).GetProperty(name) != null;
}

private static MemberExpression GetMemberInfo(Expression method)
{
    LambdaExpression lambda = method as LambdaExpression;
    if (lambda == null)
        throw new ArgumentNullException("method");

    MemberExpression memberExpr = null;

    if (lambda.Body.NodeType == ExpressionType.Convert)
    {
        memberExpr = 
            ((UnaryExpression)lambda.Body).Operand as MemberExpression;
    }
    else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
    {
        memberExpr = lambda.Body as MemberExpression;
    }

    if (memberExpr == null)
        throw new ArgumentException("method");

    return memberExpr;
}

这段内容 shamelessly 来自于这里:从Lambda表达式中获取属性名称

但是这是一个略微不同的问题,所以我发布了完整的答案。

我刚刚注意到,在我提供的链接中,第二个答案比这个要简单得多。ChrisWue 的回答在这个帖子中涵盖了这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接