- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试实现一个复杂的构建器来帮助我的测试上下文。为此,我重构了我的代码以获得一个方法:
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>
,因此类型转换。
我非常想:
(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>>
是不正确的,因为我们不知道该函数的参数是否真的是 PersonBuilder
或 IBuilder<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/
我是一名优秀的程序员,十分优秀!