Создание сложных типов со всеми эквивалентными свойствами

Есть ли в AutoFixture возможность создавать несколько экземпляров одного типа со всеми одинаковыми данными? Мои классы не сериализуемы, и мне нужны две модели, которые не являются ссылочными эквивалентами, но вместо этого имеют совпадающие свойства.

public class Foo
{
    // Many more properties and similar models needing the same semantics.
    public string Name { get; set; }
}

var a = fixture.Create<Foo>();
var b = fixture.Create<Foo>();

Assert.False(ReferenceEquals(a, b));
Assert.Equal(a.Name, b.Name);

person Ritmo2k    schedule 07.11.2017    source источник


Ответы (1)


Я не думаю, что AutoFixture может это сделать, но Albedo может. Хотя это всего лишь пробный код, я надеюсь, он должен проиллюстрировать общую идею.

Создайте новый класс, производный от ReflectionVisitor<T>:

public class PropertyCopyVisitor<T> : ReflectionVisitor<T>
{
    private readonly T source;
    private readonly T destination;

    public PropertyCopyVisitor(T source, T destination)
    {
        this.source = source;
        this.destination = destination;
    }

    public override IReflectionVisitor<T> Visit(
        PropertyInfoElement propertyInfoElement)
    {
        var pi = propertyInfoElement.PropertyInfo;
        pi.SetValue(this.destination, pi.GetValue(this.source));
        return this;
    }

    public override T Value
    {
        get { return this.destination; }
    }
}

Ключевой частью реализации является перегрузка Visit, где она использует Reflection для копирования каждого свойства из объекта source в destination.

Поскольку эта реализация изменяет destination, свойство Value никогда не используется, но оно должно присутствовать, потому что оно abstract в _9 _...

Теперь вы можете написать свой тест как:

var fixture = new Fixture();
var a = fixture.Create<Foo>();
var b = fixture.Create<Foo>(); // Or just create a new, empty Foo...
// This copies all properties from a to b:
new TypeElement(typeof(Foo)).Accept(new PropertyCopyVisitor<Foo>(a, b));

Assert.False(ReferenceEquals(a, b));
Assert.Equal(a.Name, b.Name);

Здесь я все еще использовал fixture для создания b, но вам не нужно этого делать, потому что все свойства в любом случае будут перезаписаны. Если Foo имеет конструктор без параметров, вы можете вместо этого просто использовать new Foo(); это не имело бы значения.

Это доказательство концепции явно копирует только свойства. Если вам также нужно скопировать поля, вам также придется переопределить соответствующий метод Visit. Кроме того, если рассматриваемые объекты принимают аргументы конструктора, вам также придется иметь дело с ними явно.

Если вам утомительно писать new TypeElement(typeof(Foo)).Accept(new PropertyCopyVisitor<Foo>(a, b));, я уверен, что вы найдете способ написать вспомогательный метод для этого.

В качестве дополнительного примечания, PropertyCopyVisitor не должен быть общим, потому что на самом деле он ни для чего не использует аргумент типа T. Мне просто нравится безопасность типов, которую это дает конструктору ...

person Mark Seemann    schedule 07.11.2017