Поля на лету от статического отражения?

Я изучал статическое отражение с помощью выражений LINQ - очень круто!

У меня была одна мысль - возможно ли, чтобы один класс "генерировал" поля в одном классе на основе статического отражения, сделанного в другом классе? Я специально думаю о модели Строителя, которую видел здесь много раз. Я хотел бы сделать регистрацию свойств в стиле беглого nhibernate, которая "генерирует" поля в компоновщике, которые соответствуют классу, который я хочу построить. Примерно так:

public class Color
{
    private Color()
    {
    }
    public string Name { get; private set; }

    public class Builder : BuilderBase<Color>
    {
        public Builder()
        {
            Property(x => x.Name);
        }
        public Build()
        {
            return built_up_color;
        }
    }
}

и поддерживать синтаксис конструктора, как это:

Color c = new Color.Builder() { Name = "Red" }.Build();

Смысл всего этого состоит в том, чтобы уменьшить количество раз, которое я должен повторить, определяя свойства цвета. Я играл с этим:

public class Color
{
    private Color()
    {
    }
    public string Name { get; private set; }

    public class Builder
    {
        private Color _color = new Color();
        public string Name
        {
            get { return _color.Name; }
            set { _color.Name = value; }
        }

        public Build()
        {
            return _color;
        }
    }
}

который, безусловно, работает и перечисляет свойства столько же раз, но выглядит более словесным и менее гибким. Похоже, я должен быть в состоянии сделать что-то анонимно-типа-у здесь?

3 ответа

Решение

Стоит отметить, что иметь класс с именем Color, конфликтующий с System.Drawing.Color, вероятно, плохая идея.

Это может привести к путанице в других (что еще хуже, System.Drawring.Color имеет семантику значений, в то время как ваш класс имеет семантику ссылок, которая может привести к дальнейшей путанице)

Я хотел бы отметить, что вы действительно хотите именованные необязательные аргументы. Я хотел бы предположить, что введение громоздких классов Builder теперь будет более трудоемким, и, как только вы доберетесь до C# 4.0, переходить к ним стало бы более болезненным. Вместо этого сделайте конструкторы, которые требуются (или, если необходимо, чтобы избежать коллизий сигнатур типов, статические фабричные методы в классе)

Я думаю, что это невозможно, вы не можете создавать участников, кроме как объявив их явно. Укусить пулю и объявить конструктор для Color,

PS: я думаю, что статическое отражение является неправильным, единственное, что статично, это поиск члена, на которого вы хотите сослаться - хорошая вещь, насколько это возможно, но это не очень далеко.

Меньше кода для написания, но с использованием отражения для установки значений.

Хитрость заключается в использовании инициализаторов коллекции. это небезопасно.

public class Color
{
    private Color()
    {
    }
    public string Name { get; private set; }
    public int Prop2 { get; private set; }

    public class Builder : Builder<Color>
    {
        public Builder()
        {
            // possible
            _instance.Name = "SomeDefaultValue";
        }
    }
}

class Builder<T> : IEnumerable<string>
{
    protected T _instance = Activator.CreateInstance(typeof(T));

    public void Add<TProperty>(Expression<Func<T, TProperty>> prop, TProperty value)
    {
        StaticReflection.GetPropertyInfo(prop).SetValue(_instance, value, null);
    }

    public static implicit operator T(Builder<T> builder)
    {
        return builder.Build();
    }

    public T Build()
    {
        return _instance;
    }

    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        // e.g. return iterator over the property names
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<string>)this).GetEnumerator();
    }
}

и вызвать синтаксис

var color = new Color.Builder
{
    { x => x.Name, "foo" },
    { x => x.Prop2, 5 }
}.Build();

// or

var color = new Builder<Color>
{
    { x => x.Name, "foo" },
    { x => x.Prop2, 5 }
}.Build();

// or

Color color = new Builder<Color>
{
    { x => x.Name, "foo" },
    { x => x.Prop2, 5 }
};
Другие вопросы по тегам