Может ли класс C # ссылаться на свой собственный тип как универсальный тип? - PullRequest
0 голосов
/ 03 мая 2018

Фон

Мы используем шаблон компоновщика в нескольких местах по всему приложению. До сих пор мы писали следующий метод в некоторых наших сборщиках, который хорошо работал.

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?

Мне бы очень хотелось получить синтаксический признак отсутствия необходимости явно передавать тип строителя.

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Потенциал для возврата функции with AbstractBuilder<TType>

Например:

public abstract class AbstractBuilder<T>
{
    internal T entity;

    public AbstractBuilder<T> 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 this;
    }

    public T Build()
    {
        return this.entity;
    }
}

Затем вы можете сделать желаемое простое расширение:

public class MyBuilderClass : AbstractBuilder<PaymentRecord>

И назовите это так:

var builder = new MyBuilderClass();
var record = builder
            .With(f => f.TrackingRecord, new MyTrackingRecord())
            .Build();

Недостатком является то, что он ограничивает ваш свободный API для абстрактного класса после вызова with, если только вы не переопределите вызов функции для возврата определенного типа компоновщика.

0 голосов
/ 03 мая 2018

Нет, дженерики не любят делать такие вещи. Вам нужно будет передать аргумент типа.

Общее примечание; если вы часто строите такие объекты, отражение может стать довольно дорогим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...