C# 如何在c中将额外数据传递到泛型方法#

C# 如何在c中将额外数据传递到泛型方法#,c#,generics,C#,Generics,我们有一个wcf web服务API,它有一些通用代码,我们将这些代码包装到一个通用方法中,以避免在每个web服务方法中编写相同的代码。这看起来是这样的: TResult SafeMethodCall<T, TResult>(Func<T, TResult, TResult> body, T request) where TResult : ServiceResponse, new() where T : RequestBase {

我们有一个wcf web服务API,它有一些通用代码,我们将这些代码包装到一个通用方法中,以避免在每个web服务方法中编写相同的代码。这看起来是这样的:

TResult SafeMethodCall<T, TResult>(Func<T, TResult, TResult> body, T request)
        where TResult : ServiceResponse, new()
        where T : RequestBase
    {
        if (request == null)
            throw new ArgumentNullException("request");

        var response = new TResult();

        try
        {
            response = body(request, response);
        }
        catch (Exception ex)
        {
            AddServiceError(response, ex);
        }
        finally
        {
            AddAuditData(request, response);
        }

        return response;
    }
每个web服务方法都有自己版本的响应和请求类,这些类继承自此方法中引用的基本类

我的问题是,对于一个或两个web服务方法,我没有访问要记录的参数的权限,但是我需要做一些工作来获取它,我不确定如何将它传递到通用方法来处理它

我可以通过使用全局变量或将其添加到响应类中来实现这一点,但从编程风格的角度来看,这两种方法都显得相当拙劣


我想知道是否有人对处理这个问题的“好”方法有其他建议?

据我所知,您需要通过反射调用泛型方法

如果是,请使用System.ReflectionMethodInfo.MakeGenericMethod(参数类型[])

所以你必须这样做

  typeof(TargetClass).GetMethod("TargetMethod").MakeGenericMethod(typeof(T1),typeof(T2)....).Invoke(obj,args);
这里是相关帖子


这是有关此主题的msdn页面

首先,您不应该使用反射来提取值。使用公共接口可以很好地解决这个问题

现在谈谈你的问题。您可以将signinId作为可选参数传递给
SafeMethodCall
,这样您就不会破坏现有合同。然后从那里将其传递到
AddAuditData

TResult SafeMethodCall<T, TResult>(Func<T, TResult, TResult> body, T request, string signinId = null)
    where TResult : ServiceResponse, new()
    where T : RequestBase
{
        // ...

        AddAuditData(request, response, signinId);

        // ...
}

或者,您可以传递一个函数,该函数将返回SigniID或一个对象,该对象将提供值。

我想我最好详细说明一下我的解决方案。问题是我需要能够将更多的数据从函数调用体传递到我的审计过程中,我不确定如何为通用函数做到这一点

因此,第一部分是认识到

 Func<T, TResult, TResult> body
函数体
只是一个内置的委托类型,所以我需要用我自己的版本替换它,该版本还包含一个out参数

private delegate TResult MyFunc< T1,  T2,  T3,  TResult>(T1 arg1, T2 arg2, out T3 arg3);
私有委托TResult MyFunc(T1 arg1,t2arg2,out T3 arg3);
然后,我可以更改SafeMethodCall中的代码以使用此委托

TResult SafeMethodCall<T, TResult>(MyFunc<T, TResult, string, TResult> body, T request)
        where TResult : ServiceResponse, new()
        where T : RequestBase
    {
        if (request == null)
            throw new ArgumentNullException("request");

        var response = new TResult();
        string id = null;
        try
        {
            LogServiceEntry(request);

            response = body(request, response,out id); //from the delegate
        }
        catch (Exception ex)
        {
            AddServiceError(response, ex);
        }
        finally
        {
            AddAuditData(request, response, id);
            LogServiceExit(response);
        }

        return response;
    }
TResult安全方法调用(MyFunc主体,T请求)
其中TResult:ServiceResponse,new()
其中T:RequestBase
{
if(请求==null)
抛出新的ArgumentNullException(“请求”);
var response=new TResult();
字符串id=null;
尝试
{
LogServiceEntry(请求);
response=body(请求、响应、输出id);//来自委托
}
捕获(例外情况除外)
{
AddServiceError(响应,ex);
}
最后
{
AddAuditData(请求、响应、id);
LogServiceExit(响应);
}
返回响应;
}
这意味着在我调用这个函数的web服务方法中,我可以编写一些代码来生成审计所需的额外参数

public ResetPasswordResponse ResetPassword(ResetPasswordRequest resetPasswordRequest)
    {

        return SafeMethodCall<ResetPasswordRequest, ResetPasswordResponse>
            ((ResetPasswordRequest request,
                ResetPasswordResponse response, out string signInIdentifier) =>
        {
            signInIdentifier = null;
            if (!_validator.ValidateModel(request, response))
                return response;
            var signIn =
                _manager.GetSignInByPasswordResetToken(request.PasswordResetToken);
            if (signIn != null)
            {
                signInIdentifier = signIn.SignInIdentifier.ToString();              
            }

            var result = _manager.ResetPassword(request.SiteIdentifier,
            request.PasswordResetToken, request.Password);

            if (!result)
            {
                AddServiceError(response, "The password could not be reset",
                    ErrorType.GeneralError);
            }

            return response;
        }, resetPasswordRequest);
    }
public ResetPasswordResponse ResetPassword(ResetPasswordRequest ResetPasswordRequest)
{
返回SafeMethodCall
((ResetPasswordRequest请求,
ResetPasswordResponse响应,输出字符串符号标识符)=>
{
signInIdentifier=null;
if(!\u validator.ValidateModel(请求、响应))
返回响应;
var信号=
_manager.GetSignInByPasswordResetToken(request.PasswordResetToken);
如果(签名!=null)
{
signInIdentifier=signIn.signInIdentifier.ToString();
}
var result=\u manager.ResetPassword(request.SiteIdentifier,
request.PasswordResetToken,request.Password);
如果(!结果)
{
AddServiceError(响应“密码无法重置”,
ErrorType.GeneralError);
}
返回响应;
},重置密码请求);
}

Hi Tom,是的,这就是我想要了解的——格式化方法调用以传入我需要的参数的最佳方式是什么(或者说,body方法是否需要不同的委托结构)。我会看看是否能按你的建议工作
TResult SafeMethodCall<T, TResult>(MyFunc<T, TResult, string, TResult> body, T request)
        where TResult : ServiceResponse, new()
        where T : RequestBase
    {
        if (request == null)
            throw new ArgumentNullException("request");

        var response = new TResult();
        string id = null;
        try
        {
            LogServiceEntry(request);

            response = body(request, response,out id); //from the delegate
        }
        catch (Exception ex)
        {
            AddServiceError(response, ex);
        }
        finally
        {
            AddAuditData(request, response, id);
            LogServiceExit(response);
        }

        return response;
    }
public ResetPasswordResponse ResetPassword(ResetPasswordRequest resetPasswordRequest)
    {

        return SafeMethodCall<ResetPasswordRequest, ResetPasswordResponse>
            ((ResetPasswordRequest request,
                ResetPasswordResponse response, out string signInIdentifier) =>
        {
            signInIdentifier = null;
            if (!_validator.ValidateModel(request, response))
                return response;
            var signIn =
                _manager.GetSignInByPasswordResetToken(request.PasswordResetToken);
            if (signIn != null)
            {
                signInIdentifier = signIn.SignInIdentifier.ToString();              
            }

            var result = _manager.ResetPassword(request.SiteIdentifier,
            request.PasswordResetToken, request.Password);

            if (!result)
            {
                AddServiceError(response, "The password could not be reset",
                    ErrorType.GeneralError);
            }

            return response;
        }, resetPasswordRequest);
    }