解決方案需要多個一點點先進PostSharp功能。
您需要能夠從您的方面訪問「條件字段」,並且您需要能夠配置哪個字段是「條件字段」。不幸的是C#允許你指定常量表達式作爲屬性參數。唯一的方法(我知道)使用字符串指定「條件字段」名稱:
[Conditional("Initialized", "Awesome text"]
void Method1()
{
//do stuff;
}
的問題是,智能感知不能與字符串的工作,但你可以在你的方面驗證領域的存在。
您可以通過使用ImportLocationAdviceInstance和實施IAdviceProvider導入目標類的任何領域:
[PSerializable]
public class ConditionalAttribute : InstanceLevelAspect, IAdviceProvider
{
private string conditionFieldName;
private string awesomeText;
public ILocationBinding ConditionBindingField;
public ConditionalAttribute(string conditionFieldName, string awesomeText)
{
this.conditionFieldName = conditionFieldName;
this.awesomeText = awesomeText;
}
public IEnumerable<AdviceInstance> ProvideAdvices(object targetElement)
{
var targetType = (Type) targetElement;
var bindingFieldInfo = this.GetType().GetField("ConditionBindingField", BindingFlags.Instance | BindingFlags.Public);
foreach (
var field in
targetType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic))
{
if (field.Name == conditionFieldName)
{
if (field.FieldType.IsAssignableFrom(typeof(bool)))
{
yield return new ImportLocationAdviceInstance(bindingFieldInfo, new LocationInfo(field));
yield break;
}
{
Message.Write(MessageLocation.Of(targetType), SeverityType.Error, "ERR002", $"{targetType.Name} contains {field.FieldType.Name} {conditionFieldName}. {conditionFieldName} has to be bool.");
yield break;
}
}
}
Message.Write(MessageLocation.Of(targetType), SeverityType.Error, "ERR001", $"{targetType.Name} doesn't contain {conditionFieldName}");
}
}
現在,ConditionBindingField
或者包含綁定到「條件字段」,或PostSharp發出ERR001或ERR002如果「條件字段「的名稱不存在或與bool
以外的其他類型聲明。
下一步是監聽目標類中的方法與驗證代碼:
[OnMethodInvokeAdvice]
[MethodPointcut("SelectMethods")]
public void OnInvoke(MethodInterceptionArgs args)
{
bool conditionFieldValue = (bool)ConditionBindingField.GetValue(args.Instance);
if (!conditionFieldValue)
{
throw new InvalidOperationException(awesomeText);
}
args.Proceed(); // call original method body
}
PostSharp截獲SelectMethods
方法與OnInvoke方法中的代碼提供的每個方法。問題是你不想用「條件字段」檢查來攔截Init
方法,否則對這個方法的調用會拋出一個帶有「真棒文本」的異常,並且不可能初始化一個類。所以你必須標記不能被攔截的方法。您可以使用慣例和把同一個名字給所有Init
方法,或者你可以標記Init
方法與屬性:
[AttributeUsage(AttributeTargets.Method)]
public class InitAttribute : Attribute
{
}
您可以使用MethodPointcut選擇公共實例方法,而沒有Init
屬性:
private IEnumerable<MethodInfo> SelectMethods(Type type)
{
const BindingFlags bindingFlags = BindingFlags.Instance |
BindingFlags.DeclaredOnly | BindingFlags.Public;
return type.GetMethods(bindingFlags)
.Where(m => !m.GetCustomAttributes(typeof(InitAttribute)).Any());
}
有條件方面的使用示例:
[Conditional("Initialized", "Awesome text")]
class MyClass
{
bool Initialized;
[Init]
void Init()
{
Initialized = true;
}
void Method1()
{
//do stuff;
}
}
編輯:有可能標記「cond銀行足球比賽場」由一個屬性,而不是名稱指定爲字符串:
[Conditional("Awesome text")]
class MyClass
{
[ConditionField]
bool Initialized;
[Init]
void Init()
{
Initialized = true;
}
void Method1()
{
//do stuff;
}
}
凹凸........... – Xtro
您可以將合同領域和(自動)性能以及。這可以通過PostSharp實現:'[必需的]字符串f1;','[必需的] public string P1 {get;組; }'。將值分配給字段或屬性時,會觸發驗證。它是否能解決您的需求?如果沒有,請你能更詳細地描述你的用例嗎? –
我添加了我的用例 – Xtro