【问题标题】:How to let an Attribute in property 'A' know the existence of property 'B'?如何让属性“A”中的属性知道属性“B”的存在?
【发布时间】:2016-04-18 19:15:53
【问题描述】:

如何让一个属性中的一个Attribute知道另一个属性的存在?

假设我有这门课,还有很多其他的:

public class MyClass
{
    [CheckDirty] //a custom attribute (that it is empty for now)
    public int A { get; set; }
    public int B { get; set; }

    public string Description { get; set; }
    public string Info { get; set; }
}

在我们程序的某个地方,如果我们想查看一个对象是否更改了任何 CheckDirty 属性上的值,例如假设它与 DB 不同,MyPropertyUtils.GetPropertiesIfDirty() 会这样做,给我们一个更改的属性数组,on具有该属性的任何属性:

PropertyInfo[] MyPropertyUtils.GetPropertiesIfDirty(SomeBaseObject ObjectFromDB, SomeBaseObject NewValues);

完美。

所以,假设 A 已更改,在这种情况下,Info 包含我们需要的一些信息(在另一个类中可能是任何其他属性)。如果我们想要“A”,我们只需 property.GetValue(NewValues, null);

但我们不想要 'A' 的值,我们想要 'A' 或 CheckDirty 告诉我们在哪里读取我们想要的一些数据。如何告诉我的属性 CheckDirty 从哪里获取值?

我正在考虑给CheckDirty 一个表达式,但是属性的参数“必须是属性参数类型的常量表达式、typeof 表达式或数组创建表达式”(这就是 VS 所说的)。 所以我决定,“好吧,让我们给它一个带有属性名称的字符串”,所以我的尝试失败了:

(这是我们需要处理的所有代码,其余的只是给出某种上下文示例)

public class CheckDirty : Attribute
{
    public String targetPropertyName;

    public CheckDirty(String targetPropertyName)
    {
        this.targetPropertyName = targetPropertyName;
    }
}

public class MyClass
{
    //Code fails on this line
    [CheckDirty(BoundPropertyNames.Info)]
    public int Id { get; set; }

    public string Info { get; set; }

    public static class BoundPropertyNames
    {
        public static readonly string Info =   ((MemberExpression)
                                                        ((Expression<Func<MyClass, string>>)
                                                            (m => m.Info)
                                                        ).Body
                                                    ).Member.Name;
    }
}

这是我得到的错误:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type  

我们不想将属性的名称作为String saing [CheckDirty("Info")] 传递,因为这样如果将来有人更改类,具体来说就是属性名称,编译时不会抛出任何错误通过它,仅在运行时发生错误,当对该字段进行“编辑”时。或者它可能不会做任何事情,因为它找不到该属性。

知道如何不使用强类型字符串作为属性名称吗?

【问题讨论】:

  • 可以使用 Visual Studio 2015 吗?如果是这样,请使用nameof operator.
  • 我使用的是 VS 2013。不是我的电脑,无法安装。
  • 也将一个属性附加到另一个属性,并使用唯一的字符串链接它们,该字符串除了链接两个属性之外没有其他用途。您必须在属性中使用常量表达式,所以除了您说不能使用的新 nameof 运算符之外,没有其他办法。

标签: c# properties custom-attributes


【解决方案1】:

你可以使用这样的东西,首先声明一个接口,每个需要脏检查的类都会实现这个接口:

interface IDirtyCheckPropertiesProvider {
   string GetPropertyName(string dirtyProperty);
}

然后像这样实现它

class DataEntity : IDirtyCheckPropertiesProvider {
    [CheckDirty]
    public int Id { get; set; }

    public string Info { get; set; }

    string GetPropertyName(string dirtyProperty) {
        if (GetPropertyNameFromExpression(x => Id) == dirtyProperty)
            return GetPropertyNameFromExpression(x => Info);

        return null;
    }
}

在负责处理脏检查的类中,您必须使用此接口来获取目标属性名称。 使用反射 API 可能会进一步删除太多样板。

另一方面,使用字符串作为属性名称看起来更简单。如果您使用 Resharper 之类的工具 - 使用字符串是一个可行的选项 - Resharper 将在您更改属性名称时自动重构字符串。 很长一段时间以来,在 WPF INotifyPropertyChanged 的​​实现中使用了字符串属性名称。

正如 cmets 建议的那样,nameof 是 VS2015 中的最佳选择。

【讨论】:

  • 谢谢。在适应我的情况后,它就像一个魅力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 2015-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多