如何将方法作为另一个方法的参数传递

时间:2012-07-21 18:02:41

标签: c#

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

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 ...
        ...            
    }
}

有什么办法吗?

6 个答案:

答案 0 :(得分:7)

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

某些对象具有isDisposed属性,如果您的父实现了该属性,并且这是您不想调用方法的唯一时间,那么是。否则没有。如果您控制父项的源,您可以添加一个符合您需要的属性。

如果您不控制源并且想要检查多于isDisposed或者父级没有实现isDisposed,您可能能够检查公开的属性,但通常您应该假设如果方法暴露于公众,任何时候都可以接听。如果你通过反思调用私人方法,那么你就是冒险。

编辑以回复评论: 根据您的描述,代表不会通过向父级添加属性和方法来为您提供任何额外的功能(如果您不控制源,它们根本不会帮助)。处理您描述的场景的最佳方法(CAR.ENGINE.START失去气体时,Start方法要么抛出异常,要么返回值指示尝试启动引擎的结果)。

答案 1 :(得分:2)

答案 2 :(得分:0)

使用func Func<T, TResult> link

答案 3 :(得分:0)

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

“NS.Child.ThirdMethod”例如。

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

但是,此方法不符合OOP概念规则:基类应该对其子类没有任何了解。 最好使用某种锁定机制告诉孩子他们无法访问资源。

答案 4 :(得分:0)

如果这些方法是子类的原生方法,则父级无法确切了解它们。如果你甚至可以看到代码,那么Rice's Theorem会给你带来各种各样的问题。同样的问题(但程度较小),如果它们是父类的原生并且正在孩子中被覆盖,因为你不能真正保证子类将完成所有(并且只有那些事情)父类上课;事实上,你可以保证它会做某种不同的事情。 (如果没有,为什么要覆盖?)

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

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

答案 5 :(得分: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。