Фон
Мы используем шаблон компоновщика в нескольких местах по всему приложению.
До сих пор мы писали следующий метод в некоторых наших сборщиках, который хорошо работал.
public class MyBuilderClass
{
private MyConcreteType entity;
public MyBuilderClass() { this.entity = new MyConcreteType(); }
public MyBuilderClass With<TProperty>(Expression<Func<T, TProperty>> expressionToFindProperty, TProperty valueToSet)
{
MemberExpression member = (MemberExpression)expressionToFindProperty.Body;
PropertyInfo property = (PropertyInfo)member.Member;
property.SetValue(this.entity, valueToSet, null);
return this;
}
}
Позволяет нам делать что-то вроде:
new MyBuilderClass().With(x=> x.MyProperty, "TheValue")
И это означает, что MyProperty
в данном случае является строкой.
Цель
Это полезно, поэтому мы хотели бы сделать это абстрактно. Что-то вроде:
public abstract class AbstractBuilder<T, TBuilder> where TBuilder : AbstractBuilder<T, TBuilder>
{
internal T entity;
public TBuilder With<TProperty>(Expression<Func<T, TProperty>> expressionToFindProperty, TProperty valueToSet)
{
// Example usage: With(x => x.TrackingRecord, new TrackingRecord());
MemberExpression member = (MemberExpression)expressionToFindProperty.Body;
PropertyInfo property = (PropertyInfo)member.Member;
property.SetValue(this.entity, valueToSet, null);
return (TBuilder)this;
}
public T Build()
{
return this.entity;
}
}
Итак, наш бетонщик будет выглядеть так:
public class MyBuilderClass : AbstractBuilder<MyType, MyBuilderClass>
{
// Code here
}
Проблема / Вопрос
В приведенном выше примере нам нужно использовать MyBuilderClass : AbstractBuilder<MyType, MyBuilderClass>
, дважды ссылаясь на MyBuilderClass
, чтобы универсальный тип TBuilder
нашего абстрактного компоновщика работал правильно.
Есть ли в этом случае изменение, которое мы могли бы внести в AbstractBuilder
, чтобы синтаксис для наших дочерних классов можно было сократить с:
public class MyBuilderClass : AbstractBuilder<PaymentRecord, MyBuilderClass>
до
public class MyBuilderClass : AbstractBuilder<PaymentRecord>
где TBuilder
определяется как MyBuilderClass
?
Мне бы очень хотелось получить синтаксический признак отсутствия необходимости явно передавать тип строителя.