c#func参数未被使用

时间:2016-11-02 11:53:09

标签: c# design-patterns delegates aop func

我有一个记录服务输入/输出的遗留应用程序。目前,每个方法都有相同的行来记录请求和响应对象。我想使用AOP,但不添加任何额外的工具(Postsharp,Castle等),或将每个服务类包装到另一个类(ServiceWrapper)。

为了做到这一点,我试图创建一个Generic类,它知道它应该记录请求和响应对象。这是我正在尝试的内容:

using System;

namespace ProxyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var request = "request";
            var fooService = new FooService();

            ServiceProxy.Invoke(r => fooService.DoFoo(request), "abc");

            Console.Read();
        }
    }

    class ServiceProxy
    {
        public static void Invoke(Func<object, object> service, object request)
        {
            Console.WriteLine("input:" + request);

            var response = service(request);

            Console.WriteLine("output:" + response);
        }
    }

    class FooService
    {
        public string DoFoo(object a)
        {
            return a +  ": returning: Do Foo";
        }
    }

}

虽然它在工作,但是&#34; abc&#34; string只是编译应用程序,但它没有被用作请求参数。如果我删除它,代码不会编译。我错过了什么吗?

更新

更改为以下功能:

static void Main(string[] args)
    {
        var request = "request";
        var fooService = new FooService();

        ServiceProxy.Invoke(r => fooService.DoFoo(r), request);

        Console.Read();
    }

4 个答案:

答案 0 :(得分:1)

您应该这样称呼它:

class Program
{
    static void Main(string[] args)
    {
        var request = "request";
        var fooService = new FooService();

        ServiceProxy.Invoke(fooService.DoFoo, "abc"); // lose the DoFoo parameter.

        Console.Read();
    }
}

您应该将DoFoo作为Func传递,而不是调用它。您还应将方法签名更改为:

class FooService
{
    public object DoFoo(object a)
    {
        return a +  ": returning: Do Foo";
    }
}

答案 1 :(得分:1)

对于此任务,您只需在调度程序上添加日志记录行为即可。 首先,使用以下内容创建ServiceBehavior:

public class ServiceLoggingBehavior : Attribute, IServiceBehavior
{
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
        {
            foreach (OperationDescription operation in endpoint.Contract.Operations)
            {
                IOperationBehavior behavior = new LoggingOperationBehavior();
                operation.Behaviors.Add(behavior);
            }
        }
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

然后你需要创建操作行为:

internal class LoggingOperationBehavior : IOperationBehavior
{
    public void Validate(OperationDescription operationDescription)
    {

    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Invoker = new LoggingOperationInvoker(dispatchOperation.Invoker, dispatchOperation);
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {

    }

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }
}

最后为服务器端的所有方法创建调用程序:

internal class LoggingOperationInvoker : IOperationInvoker
{
    private readonly IOperationInvoker _baseInvoker;
    private readonly string _operationName;

    public LoggingOperationInvoker(IOperationInvoker baseInvoker, DispatchOperation operation)
    {
        _baseInvoker = baseInvoker;
        _operationName = operation.Name;
    }

    public bool IsSynchronous
    {
        get { return _baseInvoker.IsSynchronous; }
    }

    public object[] AllocateInputs()
    {
        return _baseInvoker.AllocateInputs();
    }

    public object Invoke(object instance, object[] inputs, out object[] outputs)
    {
        var sw = new Stopwatch();
        try
        {
            LogBegin();
            sw.Start();
            var response = _baseInvoker.Invoke(instance, inputs, out outputs);
            return response;
        }
        finally
        {
            sw.Stop();
            LogEnd(sw.Elapsed);
        }
    }

    private void LogBegin()
    {
        //you can log begin here.
    }

    private void LogEnd(TimeSpan elapsed)
    {
        //you can log end here.
    }

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
    {
        return _baseInvoker.InvokeBegin(instance, inputs, callback, state);
    }

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
    {
        return _baseInvoker.InvokeEnd(instance, out outputs, result);
    }
}

如果要记录请求,可以在Invoke方法中序列化并记录输入变量。对于响应 - 只需序列化并记录响应变量。

最终,最愉快的部分,只需附加属性:

[ServiceLoggingBehavior]
public MyService : IMyServiceContract
{
    ...
}

答案 2 :(得分:1)

您的Invoke - 方法明确要求提供Func - 和object - 参数,因此您必须同时提供这两个参数。当你省略其中一个参数时,不知道你期待什么。我假设您要让Func返回由特定request - 对象创建的响应。此外,将请求和响应参数设为通用可能是个好主意:

class Program
{
    static void Main(string[] args)
    {
        var request = "request";
        var fooService = new FooService();

        ServiceProxy.Invoke(r => fooService.DoFoo(r), request);

        Console.Read();
    }
}

class ServiceProxy
{
    public static void Invoke<TRequest, TResponse>(Func<TRequest, TResponse> service, TRequest request)
    {
        Console.WriteLine("input:" + request.ToString());

        var response = service(request);

        Console.WriteLine("output:" + response.ToString());
    }
}

Invoke - 调用可以进一步简化为ServiceProxy.Invoke(fooService.DoFoo, request);

答案 3 :(得分:0)

感谢所有回复。我能够实现我正在寻找的东西:

    static void Main(string[] args)
    {
        var request = "request";
        var fooService = new FooService();

        ServiceProxy.Invoke(fooService.DoFoo, request);

        Console.Read();
    }

static void Main(string[] args)
    {
        var request = "request";
        var fooService = new FooService();

        ServiceProxy.Invoke(r => fooService.DoFoo(r), request);

        Console.Read();
    }