【问题标题】:how to pass a service reference delegate into a generic method with error handling如何将服务引用委托传递给具有错误处理的通用方法
【发布时间】:2013-06-19 01:13:45
【问题描述】:

我不确定如何最好地描述我想要的东西,所以我将从高层次开始,然后回顾我对实施的想法。

使用 c# 我正在尝试创建一个具有通用返回类型的方法,并将服务引用中的方法作为参数。

这个通用方法将新建服务引用,调用我传入的服务引用的方法,执行服务引用所需的所有错误处理和检查,然后关闭或中止它并返回结果来电。

这样的伪代码:

public T CallServiceReference<T>(method serviceRefMethod) {
  T result = null;
  ServiceReference svcClient = new ServiceReference.Client();
    try {
      result = svcClient.serviceRefMethod;
      svcClient.Close();   
    } catch (ExceptionType ex) {
      // log error message
      svcClient.Abort();
      throw;
    }
  return result;
}

这在 C# 中可能吗?我正在寻找泛型和代表。我的主要问题之一是在没有实例化服务引用的情况下将服务引用的方法委托给一个。如果我必须实例化服务引用,我想我还不如为每个方法调用放置所有的关闭、中止和错误处理。

我正在研究不同的设计模式,虽然有点困难,因为我不知道我正在寻找的设计模式的名称,也不知道它是否存在。

如果我可以提供任何其他信息或澄清,请告诉我。

更新(第 2 部分): 现在我正在尝试使用它调用的方法创建一个封装变量的委托。

public delegate T Del<T>();
public static IEnumerable<String> GetDataFromService(String username) {
    ServiceReference.ServiceClient client = new ServiceReference.ServiceClient();
    // the method I'm going to call returns a string array
    Del<String[]> safeClientCall = new Del<String[]>(client.DataCall);
    // the above call is what I need to use so the C# compiles, but I want to do this
    // the below code throws an error...
    Del<String[]> safeClientCall = new Del<String[]>(client.DataCall(username));
    var result = DataCallHandlerMethod(ref client, safeClientCall);
    return result;
}

基本上从我的调用方法传递用户名参数,并且该用户名参数已经定义。我不想在调用委托时定义它。有没有办法使用 c# 来做到这一点?

【问题讨论】:

  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • 你的方法需要使用反射你可以在你的代码中使用反射吗
  • 我可以在我的代码中使用反射,但是我在调​​用站点新建服务引用并将引用连同方法的委托及其参数一起传递给它的解决方案似乎就像它会工作一样。

标签: c# design-patterns generics delegates service-reference


【解决方案1】:

一般来说,你的答案中的一切都是可能的,除了这一行:

result = svcClient.serviceRefMethod;

这显然是一个至关重要的调用...为了在对象上动态调用函数,您可以做一些事情。一个简单的方法是将您的函数签名更改为:

public T CallServiceReference<T>(ServiceReference svcClient, method serviceRefMethod)

但随后调用代码需要更新 ServiceReference 并将对 svcClient.[desiredFunction] 的引用作为 serviceRefMethod 传递。

另一种方法是将您的签名更改为:

public T CallServiceReference<T>(string serviceRefMethodName)

然后使用反射找到方法并调用它。你不会得到编译时验证(所以如果你有错字,它会在运行时崩溃),但你会得到动态调用。例如:

svcClient.GetType().InvokeMember(
   methodName, /* what you want to call */

   /* 
      Specifies what kinds of actions you are going to do and where / how 
      to look for the member that you are going to invoke 
    */
   System.Reflection.BindingFlags.Public | 
     System.Reflection.BindingFlags.NonPublic |
     System.Reflection.BindingFlags.Instance | 
     System.Reflection.BindingFlags.InvokeMethod, 

   null,      /* Binder that is used for binding */
   svcClient, /* the object to call the method on */
   null       /* argument list */
 );

基于您的更新的额外信息(附注:这可能是一个单独的问题)

您现在不仅要传入一个方法,还要传入该方法的调用。由于并非每个方法都以相同的方式被调用,因此您尝试在调用站点执行此操作,但那是在您真正想要调用该方法之前。从本质上讲,您要做的是穿梭于稍后才会执行的代码(在GetDataFromService 的上下文中)。

您可以采用反射路线(在这种情况下,您可以将传递给InvokeMember 调用的参数的object[] 传递给InvokeMember,或者查看Func,它允许您创建一些您可以随时运行的代码你调用Func。例如:

 GetDataFromService(new Func<object>(() => { return client.DataCall(username); }));

【讨论】:

  • 感谢您的回答。尽管现在我面临一个新问题,但这让我走上了正轨。我正在尝试创建一个委托,该委托可以将一些变量封装到委托调用站点的方法调用中,而不是调用委托的位置。另一种说法是我想一次传递一个委托及其方法的相关参数。如果您想扩展您的答案,我将使用更多代码更新我的问题。
  • 已更新 :) 如果您在此处有进一步的更新,我可能会提出新问题。
  • 糟糕!对不起,以后不会再犯同样的错误了。我非常感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-03
  • 2020-07-28
相关资源
最近更新 更多