我对面向方面编程缺乏经验。但是,我已经阅读了PostSharp提供的相当数量的PDF和文档,我认为我理解范式的要点。我有一个非常独特的问题,我相信AOP可以用来解决它。我的困境如下:
许多类将继承自A
,可以是enabled
或disabled
。考虑B
,extends A
。如果B
是disabled
,我希望禁用所有方法执行和属性以及变量访问/修改。也就是说,如果B.ExecuteMethod();
被禁用,B.Property = newValue;
和B
将无效。此外,如果需要返回值,则如果0
为null
,则该值将默认为B
或disabled
。也就是说,我希望预期对象和值的默认值。
我正在使用PostSharp C#库,它似乎非常功能强大且发展良好。我相信我的问题可以通过AttributeInheritance
来解决。例如,A
可以定义为:
[ModularAttribute(AttributeInheritance = MulticastInheritance.Multicast)]
public class A {
private bool m_enabled;
public A(){
m_enabled = true;
}
public bool Enabled() {
get {
return m_enabled;
}
set {
m_enabled = value;
}
}
}
和B
可以extend A
。此外,我的属性ModularAttribute
可以定义为:
[Serializable]
public sealed class ModularAttribute : OnMethodBoundaryAspect {
public ModularAttribute() {
}
public override void OnEntry(MethodExecutionArgs args) {
// only execute code if enabled
}
}
此属性将应用于B
,因为B extends A
。
我的问题的根源是:我需要ModularAttribute
来引用A
的{{1}}属性,这样Enabled
只会OnEntry
执行代码是真的。由于这是类级别的方面,因此我无法将Enabled
的包装版本参数化为m_enabled
,因为它超出了范围。
我是否有办法告诉ModularAttribute
其所有者ModularAttribute
具体implement
?如果是,可以interface
访问所述ModularAttribute
的特定属性吗?如果是这样,这将解决我的问题。
为了澄清,我想“告诉”PostSharp:“使用interface
的{{1}}保证class
。所以,让ModularAttribute
访问implement C
ModularAttribute
1}}定义,因为它确保工作。“
C
可以定义为:
C
因此,在public interface C {
public bool Enabled();
}
中,我可以按照
ModularAttribute
这个问题可以被视为每个对象级别的身份验证,而不是更典型的每个用户级别。必须在每个if (attachedClass.Enabled == false) {
// don't execute code
} else {
// execute code
}
和if, else
Property
添加Method
检查extends A
似乎是一个贯穿各领域的问题。因此,我认为AOP是解决这个问题的合适选择;但是,由于我对这种范式缺乏经验,我可能会以错误的方式接近它。
非常感谢任何指导。谢谢你的帮助,
答案 0 :(得分:1)
我有点担心这种遗传可能是一个设计缺陷,或者至少是一个巨大的维护头痛,但假设它不是,让我们的士兵......
我认为没有办法完全按照自己的意愿行事。即使PostSharp具备这种能力,C#也需要在编译时知道类型(在PostSharp甚至触及它之前)。
我建议您使用CompileTimeValidate来验证方面所使用的类是否属于某种类型,并且一旦到位,您可以将args.Instance
强制转换为您的接口类型,而不必担心无效的强制转换异常。如果该类不实现IEnabled
,那么您将收到编译时错误。
这是一个简单的例子:
public interface IEnabled
{
bool Enabled { get; }
}
[Serializable]
public class ModularAttribute : OnMethodBoundaryAspect
{
public override bool CompileTimeValidate(System.Reflection.MethodBase method)
{
if(typeof(IEnabled).IsAssignableFrom(method.DeclaringType))
return true;
Message.Write(method, SeverityType.Error, "MYERR001", "Aspect can't be used on a class that doesn't implement IEnabled");
return false;
}
public override void OnEntry(MethodExecutionArgs args)
{
var obj = (IEnabled) args.Instance; // this will always be a safe cast
if(!obj.Enabled)
args.FlowBehavior = FlowBehavior.Return;
}
}
虽然有一个问题:您不希望在Enabled属性本身上使用此方面,因为这会导致堆栈溢出(即方面检查属性,导致方面检查属性等)。因此,请务必使用Enabled
排除 AttributeExclude
。
class Program
{
static void Main(string[] args)
{
var b = new B();
b.Enabled = false;
b.SomeMethod();
b.AnotherMethod();
}
}
public interface IEnabled
{
bool Enabled { get; }
}
[Modular(AttributeInheritance = MulticastInheritance.Multicast)]
public class A : IEnabled
{
[Modular(AttributeExclude = true)]
public bool Enabled { get; set; }
public void SomeMethod()
{
Console.WriteLine("in SomeMethod");
}
}
public class B : A
{
public void AnotherMethod()
{
Console.WriteLine("in AnotherMethod");
}
}