如何让属性'A'中的一个Attribute知道属性'B'的存在?
How to let an Attribute in property 'A' know the existence of property 'B'?
如何让一个 属性 中的属性知道另一个 属性 的存在?
假设我有这个 class,像这样,还有很多其他的:
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()
会执行此操作,在任何具有该属性的 属性 上,给我们一个改变的 属性s 数组:
PropertyInfo[] MyPropertyUtils.GetPropertiesIfDirty(SomeBaseObject ObjectFromDB, SomeBaseObject NewValues);
完美。
所以,假设 A
已更改,在这种情况下 Info
包含我们需要的一些信息(在另一个 class 中可能是任何其他 属性)。如果我们想要 'A' 我们就做 property.GetValue(NewValues, null);
但我们不想要 'A' 的值,我们想要 'A' 或 CheckDirty
告诉我们在哪里读取我们想要的一些数据。我如何告诉我的属性 CheckDirty
从哪里获取值?
我正在考虑给 CheckDirty
一个表达式,但是一个属性的参数 "must be a constant expression, typeof expression or array creation expression of an attribute parameter type"(VS 就是这么说的)。
所以我决定,"ok, lets give it a string with the property's name",所以我的尝试失败了:
(这是我们需要处理的所有代码,其余的只是给出某种上下文示例)
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")]
传递,因为那样的话,如果将来有人更改 class,具体来说 属性 的名称,它不会在编译时抛出错误,只会在 运行 时间发生错误,此时该字段将发生 "edit"。或者它可能不会做任何事情,因为它找不到 属性.
知道如何不使用 强类型字符串 作为 属性 名称吗?
你可以这样使用,首先声明一个接口,每个class需要脏检查的实现:
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;
}
}
在将负责处理脏检查的 class 中,您必须使用此接口获取目标 属性 名称。
使用反射 API 可以进一步删除太多的样板文件。
另一方面,使用字符串作为 属性 名称看起来更简单。如果您使用像 Resharper 这样的工具 - 使用字符串是一个可行的选项 - 当您更改 属性 名称时,Resharper 将自动重构字符串。
同样很长一段时间,字符串化的 属性 名称被用于 WPF INotifyPropertyChanged 的实现。
正如评论所建议的那样,nameof
是 VS2015 中的最佳选择。
如何让一个 属性 中的属性知道另一个 属性 的存在?
假设我有这个 class,像这样,还有很多其他的:
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()
会执行此操作,在任何具有该属性的 属性 上,给我们一个改变的 属性s 数组:
PropertyInfo[] MyPropertyUtils.GetPropertiesIfDirty(SomeBaseObject ObjectFromDB, SomeBaseObject NewValues);
完美。
所以,假设 A
已更改,在这种情况下 Info
包含我们需要的一些信息(在另一个 class 中可能是任何其他 属性)。如果我们想要 'A' 我们就做 property.GetValue(NewValues, null);
但我们不想要 'A' 的值,我们想要 'A' 或 CheckDirty
告诉我们在哪里读取我们想要的一些数据。我如何告诉我的属性 CheckDirty
从哪里获取值?
我正在考虑给 CheckDirty
一个表达式,但是一个属性的参数 "must be a constant expression, typeof expression or array creation expression of an attribute parameter type"(VS 就是这么说的)。
所以我决定,"ok, lets give it a string with the property's name",所以我的尝试失败了:
(这是我们需要处理的所有代码,其余的只是给出某种上下文示例)
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")]
传递,因为那样的话,如果将来有人更改 class,具体来说 属性 的名称,它不会在编译时抛出错误,只会在 运行 时间发生错误,此时该字段将发生 "edit"。或者它可能不会做任何事情,因为它找不到 属性.
知道如何不使用 强类型字符串 作为 属性 名称吗?
你可以这样使用,首先声明一个接口,每个class需要脏检查的实现:
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;
}
}
在将负责处理脏检查的 class 中,您必须使用此接口获取目标 属性 名称。 使用反射 API 可以进一步删除太多的样板文件。
另一方面,使用字符串作为 属性 名称看起来更简单。如果您使用像 Resharper 这样的工具 - 使用字符串是一个可行的选项 - 当您更改 属性 名称时,Resharper 将自动重构字符串。 同样很长一段时间,字符串化的 属性 名称被用于 WPF INotifyPropertyChanged 的实现。
正如评论所建议的那样,nameof
是 VS2015 中的最佳选择。