【问题标题】:Currying methods of an interface automatically in C#在 C# 中自动对接口的方法进行柯里化
【发布时间】:2017-01-13 08:10:06
【问题描述】:

假设我有一个使用 WCF 在 c# 中实例化对象的 REST 接口。假设此 REST 接口提供有关特定企业的客户的信息,例如:他们的姓名、年龄、居住县等。

REST 接口如下所示:

public interface IRestCustomerService
{
  public string CustomerName(int customerId);
  public int CustomerAge(int customerId);
  public string CustomerCountry(int customerId);
  public DateTime CustomerLastPurchaseInStore(int customerId, int storeId);
  ..
  ..
}

现在,假设我有一个班级:

public class Customer
{
  private int customerId;
  private IRestCustomerService restService;

  public Customer(int ctrId, string serviceUrl)
  {
    customerId = ctrId;
    restService = CreateConnection(serviceUrl);
  }
}

我想要的是能够通过客户类调用接口IRestCustomerService定义的方法,而不必实例化customerId参数; Customer 类应使用其成员 customerId 作为此参数。

例如:

Customer c = new Customer(1, serverUl);
string name = c.CustomerName();
DateTime lastPurchase = c.CustomerLastPurchaseInStore(5);
..

如果rest服务接口定义了很多方法,对于接口定义的每个方法,自己在客户类上写封装函数真的很繁琐。有什么办法可以自动做到这一点?

在函数式编程中,这将是微不足道的,因为我想要的是接口的 curryfied 版本。但是,如果不明确定义每个包装方法或需要具体实现的接口的新定义,我就看不到在 c# 中执行此操作的方法。

【问题讨论】:

  • 不确定它是否真的与您所追求的相匹配,但是您可以为 Customer 类创建扩展方法,而不是为 REST 服务创建接口吗?之前有人告诉我,在您的业务对象中引用服务是一个坏主意,这适用于您的示例。
  • 不清楚你真正想要什么。如果IRestCustomerService 的所有实现者都有customerId,为什么接口需要这个值?如果他们不这样做,一般解决方案将如何工作?没有customerId 的接口实现者会怎么做?
  • 您可以在IRestCustomerService 上声明一个扩展方法,该方法将通过反射检查实现类以使用适当的字段(缓存结果...使用dynamic 可能有用) ,但在您的示例中,customerId 是私有实现细节;对于该类之外的任何代码,甚至了解该领域,这将是一个主要的设计缺陷,更不用说使用它了。而且您仍然必须单独执行每种方法。
  • 如果您从一个 F# 示例(即一种函数式语言)开始,并展示 语言将如何做您想做的事情,并解释您想要什么语法在 C# 中做同样的事情,你的问题会更清楚。

标签: c# functional-programming


【解决方案1】:

首先让我们假设您可以手动执行此操作:

CustomerProxy p = new CustomerProxy(customer, service);
var name = p.GetName();

而您的“代理”只会将调用转发给服务,并传递正确的 ID:

class CustomerProxy 
{ 
    public CustomerProxy(Customer c, RestService svc)
    {
    }

    public string GetName() 
    {
        return svc.GetName(c.Id);
    }
}

现在因为这项工作太大而无法手动完成,所以您有两种方法可以解决:

  • 使用代码生成器为您生成样板代码。如果您的工具带中有代码生成工具,效率会更高。与手动完成相比,也更不容易出错。

  • 使用动态代理模式在运行时动态执行此操作。这将更难理解(也许),但最终需要处理的代码更少。您的动态代理包装器将在运行时拦截对对象的调用并传递必要的额外参数。事实上,它的工作方式与手动方法完全相同,但无需编写或生成代理层。在 .NET 上,您可以使用 Windsor DynamicProxy 库。

【讨论】:

    【解决方案2】:

    不确定 WCF 客户端类是否会容忍这种类型的探索,但我看到有人构建了一个“Curry”函数来获取带有预加载参数的 lambda:

    看看这个:Currying in C# on Code Rant

    【讨论】:

      猜你喜欢
      • 2010-09-14
      • 2014-12-30
      • 2016-06-20
      • 1970-01-01
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多