gpt4 book ai didi

c# - 如何使用泛型来处理 Action> 中特定于类型的配置?

转载 作者:行者123 更新时间:2023-11-30 16:03:59 25 4
gpt4 key购买 nike

我正在尝试实现一个复杂的构建器来帮助我的测试上下文。为此,我重构了我的代码以获得一个方法:

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> ,因此类型转换。

我非常想:

  • 不需要在 lambda 内部 而是在它的开头进行转换,例如
    (PersonBuilder personBuilder) => personBuilder.Name("SMITH") , 但这归结为 Action<PersonBuilder> 的一个实例因此同样无效;
  • 使用函数,例如 BuildSimplePerson(PersonBuilder builder)在 Add 的参数中:Add<Person>(BuildSimplePerson)

我想我可以通过两个 BuildSimplePerson 进行类型转换s 实现如:

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

但这并不是一个真正优雅的解决方案。

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

我怎样才能做得更好?

最佳答案

正如我的评论已经指出的那样,问题是您当前的代码假定 CreateBuilderOf<T>返回 PersonBuilder但它实际上可以返回任何实现 IBuilder<Person> 的东西在这种情况下,您的转换将失败。

你的代码看起来是通用的,但实际上不是。您总是希望在具体类 ( PersonBuilder ) 上工作,而不是在通用接口(interface) 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>()

但实际上,这实际上只不过是一个 new PersonBuilder() , 所以你实际上可以简单地使用

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

Configure方法将非常相似:

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

这将传递 ID,即 Configure方法将用于查找对象,该对象又传递给回调。所以Configure的第二个参数不会是 Action<IBuilder<T>>但是一个Action<T> .

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

关于c# - 如何使用泛型来处理 Action<IBuilder<T>> 中特定于类型的配置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35896113/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com