ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CodeGo.net>如何在操作>中使用泛型来处理类型特定的配置?

2019-11-19 01:07:55  阅读:192  来源: 互联网

标签:templates delegates c lambda


我正在尝试实现一个复杂的构建器来帮助我的测试环境.为此,我将代码重构为具有一个方法:

public TestContext Add<T>(Action<IBuilder<T>> configurator) where T : class, new()
{
    IBuilder<T> builder = CreateBuilderOf<T>();
    configurator(builder);
    T item = builder.GetItem();
    RepositoryOf<T>().Insert(item);
    SetCurrent(item);
    return this;
}

当我需要在调用方法时指定配置时,就会出现问题:

TestContext.Instance.Add<Person>(personBuilder => ((PersonBuilder)personBuilder).Name("SMITH"));

我需要能够在配置器中使用类型特定的方法,这些方法由具体的构建器实现,例如:

public PersonBuilder : IBuilder<Person>
{
  private Person Item;

  public PersonBuilder() { Item = new Person(); }

  public Name(string mame) { Item.Name = name; }

  public Person GetItem() { return Item; }
}

显然,传递一个Action< PersonBuilder>.作为Action< IBuilder< Person>即使PersonBuilder实现了IBuilder< Person&gt ;,也不允许这样做,因此强制转换. 我非常愿意:
>不必在lambda内部投放,而是在开始时投放,例如
(PersonBuilder personBuilder)=> personBuilder.Name(“ SMITH”),但是归结为Action< PersonBuilder>的实例.因此同样无效;
>在Add的参数中使用诸如BuildSimplePerson(PersonBuilder builder)之类的函数:Add< Person>(BuildSimplePerson)

我认为我可以通过两个BuildSimplePersons实现来进行类型转换:

private void BuildSimplePerson(IBuilder<Person> builder)
{
  BuildSimplePerson(builder as PersonBuilder);
}
private void BuildSimplePerson(PersonBuilder builder)
{
  builder.Name("SMITH");
}

但这并不是一个很好的解决方案.

我还意识到传递Action< PersonBuilder>作为Action< IBuilder< Person>错误是不正确的,因为我们不知道该函数的参数是否确实是PersonBuilder或IBuilder< Person>的任何其他实现.

我该如何做得更好?

解决方法:

正如我的评论已经指出的那样,问题在于您当前的代码假定CreateBuilderOf< T>返回PersonBuilder,但实际上可以返回实现IBuilder< Person>在这种情况下,您的演员将会失败.

您的代码看起来像是通用的,但实际上并非如此.您总是想在具体的类(PersonBuilder)上工作,而不是在通用接口IBuilder< Person>上工作.

我的理解是,您需要一个通用的Add&T避免必须针对每种类型在其内部重复该代码的方法.

这是我的方法:

public TestContext Add<T>(IBuilder<T> builder) where T : class, new()
{
    T item = builder.GetItem();
    RepositoryOf<T>().Insert(item);
    SetCurrent(item);
    return this;
}

您可以这样称呼它:

TestContext.Instance.Add<Person>(CreatePersonBuilder().Name("SMITH"));

显然,您需要为每种要添加的类型都具有一个CreateXBuilder方法.但是,我认为您至少已经隐含了这一点,因为我认为您的CreateBuilderOf< T>无论如何,方法是一个巨大的switch语句.

如果您不想创建此类方法,那么获取构建器的另一种方法将是通用方法,如下所示:

CreateBuilder<PersonBuilder>()

但是实际上,这实际上只是一个新的PersonBuilder(),因此您实际上可以简单地使用

TestContext.Instance.Add<Person>(new PersonBuilder().Name("SMITH"));

Configure方法将非常相似:

TestContext.Instance.Configure<Person>(id, p => new PersonBuilder(p).Name("SMITH"));

这将传递ID,Configure方法将使用该ID查找对象,然后将其传递给回调.因此,Configure的第二个参数将不是Action< IBuilder< T>>.但是动作< T>.

与现有代码相比,此方法还有另一个优势:
您现有的代码不仅假定PersonBuilder将是用于IBuilder< Person>的实现.不,您的代码还假定它具有一个没有参数的构造函数,而该构造函数采用一个Person.这些假设是编译器无法验证的.
使用上面显示的代码,构建器实现可以毫无问题地使用其他参数,并且编译器将验证一切正常.

标签:templates,delegates,c,lambda
来源: https://codeday.me/bug/20191118/2032196.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有