0

我需要在“父”对象中检查是否有一个可以接受的在某个特定时刻调用“子”中的某些方法。例如,父对象(组件)包括子对象(或换句话说,组件部分)并且父对象现在正在处理,因此必须禁止所有(或特定)子活动(即启动新的服务线程,将新的客户端请求入队,.. .)。

public class Parent
{
    public bool IsMethodCallAcceptable(reference_to_method) {...}
}

public class Child
{
    public int SomeMethod(int intArg, string stringArg)
    {
        if(!_parent.IsMethodCallAcceptable(reference_to_SomeMethod_with_actual_args))
            throw new ...
        ...
    }

    private void AnotherMethod(string param = null) {...}
    {
        if(!_parent.IsMethodCallAcceptable(reference_to_AnotherMethod_with_actual_args))
            throw new ...
        ...
    }

    private Guid ThirdMethod()
    {
        if(!_parent.IsMethodCallAcceptable(reference_to_ThirdMethod))
            throw new ...
        ...            
    }
}

有什么办法吗?

4

6 回答 6

7

注意:我正在回答您的问题,而不是您的标题。其他人已经回答了这个标题。

某些对象具有 isDisposed 属性,如果您的父对象实现了该属性并且这是您唯一不想调用方法的时候,那么可以。否则没有。如果您控制父级的源,则可以添加一个执行所需操作的属性。

如果你不控制源并且你想要检查的不仅仅是 isDisposed 或者父级没有实现 isDisposed,你也许可以检查公开暴露的属性,但通常你应该假设如果一个方法是公开的,可以随时调用它。如果您通过反射调用私有方法,那么您就是在冒险。

编辑以回应评论: 鉴于您的描述,委托不会为您提供任何您无法通过向父级添加属性和方法来更轻松地完成的额外功能(如果您不控制源,它们将无济于事全部)。处理您所描述的场景的最佳方法(CAR.ENGINE.START 没有汽油时,是让 Start 方法抛出异常或返回一个值,指示尝试启动引擎的结果)。

于 2012-07-21T18:17:35.253 回答
2

使用代表?

http://msdn.microsoft.com/en-us/library/ms173171%28v=vs.80%29.aspx

于 2012-07-21T18:04:51.863 回答
0

如果这些方法是子类的本机方法,则父类无法确定它们的任何信息。 赖斯定理会给你带来各种各样的问题,如果你能看到代码的话。如果它们是父类的本机并且在子类中被覆盖,则同样的问题(但程度较轻),因为您不能真正保证子类将执行父类的所有操作(并且仅执行这些操作)上课;事实上,你几乎可以保证它会做一些不同的事情。(如果没有,为什么要覆盖?)

如果它们是父类的本机并且在子类中不可覆盖,则只需检查对象是否处于执行此类操作的有效状态,如果不是则抛出异常。

至于实际的有效性检查,对于您的示例,您可以使用类似的方法bool IsDisposing();对于其他情况,您可能会以其他方式跟踪状态。例如,像这样的私有方法CanDoThisThing()可能会有所帮助。拥有一个采用通用操作名称的方法(不是操作;我们已经确定了它的不可行性)对我来说似乎有点坏了。

于 2012-07-21T18:37:38.533 回答
0

使用 funcFunc<T, TResult> 链接

于 2012-07-21T18:05:47.980 回答
0

最简单的方法是传递 URI 而不是引用:

例如“NS.Child.ThirdMethod”。

否则,委托是最接近函数引用的。如果你愿意,你可以通过它。

但是,这种方法不符合 OOP 的概念规则:基类不应该知道它的子类。最好使用某种锁定机制来告诉孩子他们无法访问资源。

于 2012-07-21T18:05:51.723 回答
0

再次谢谢大家,下面列出了第一种方法的结果

public class Component
{
    public ComponentPart SomeComponentPart1 { get; private set; }
    public ComponentPart SomeComponentPart2 { get; private set; }

    public Component()
    {
        SomeComponentPart1 = new ComponentPart(this);
        SomeComponentPart2 = new ComponentPart(this);
    }

    public bool IsMethodCallAcceptable(MethodCallExpression method, object[] parameters)
    {
        // collect needed information about caller
        var caller = (method.Object as ConstantExpression).Value;
        var methodName = method.Method.Name;
        var paramsArray = new Dictionary<string, object>();

        for (int i = 0; i < method.Arguments.Count; i++)
            paramsArray.Add((method.Arguments[i] as MemberExpression).Member.Name, parameters[i]);

        // make corresponding decisions
        if (caller == SomeComponentPart2)
            if (methodName == "SomeMethod")
                if ((int) paramsArray["intArg"] == 0 || (string) paramsArray["stringArg"] == "")
                    return false;

        return true;
    }
}

public class ComponentPart
{
    private Component Owner { get; set; }

    public ComponentPart(Component owner)
    {
        Owner = owner;
    }

    public int SomeMethod(int intArg, string stringArg)
    {
        // check if the method call with provided parameters is acceptable
        Expression<Func<int, string, int>> expr = (i, s) => SomeMethod(intArg, stringArg);
        if (!Owner.IsMethodCallAcceptable(expr.Body as MethodCallExpression, new object[] { intArg, stringArg }))
            throw new Exception();

        // do some work
        return stringArg.Length + intArg;
    }

    public void AnotherMethod(bool boolArg, Dictionary<Guid, DateTime> crazyArg, string stringArg, object objectArg)
    {
        // check if the method call with provided parameters is acceptable
        Expression<Action<bool, Dictionary<Guid, DateTime>, string, object>> expr =
            (b, times, arg3, arg4) => AnotherMethod(boolArg, crazyArg, stringArg, objectArg);
        if (!Owner.IsMethodCallAcceptable(expr.Body as MethodCallExpression, new [] { boolArg, crazyArg, stringArg, objectArg }))
            throw new Exception();

        // do some work
        var g = new Guid();
        var d = DateTime.UtcNow;
    }
}

这是如何检查方法调用的变体,可以使用相同的方法来检查属性值的变化,而某些 ComponentPart 的方法和属性可以检查一些公共 Component.State 属性(通过 ComponentPart.Owner)而不是调用 Component.IsMethodCallAcceptable或 Component.IsPropertyChangeAcceptable。

于 2012-07-22T09:44:26.980 回答