asiftasleem / nbuilder

Automatically exported from code.google.com/p/nbuilder
0 stars 0 forks source link

Extensible Property Namers #21

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
My team has adopted NBuilder on our current project.  Thanks for this very
cool tool!!!

I like the ability to specify my own property namer.  I also appreciate
ability to extend the existing namers by overriding the virtual method,
HandleUnknownType.  However, I would like to suggest making namers much
more extensible.  To illustrate my idea, I have created the following class:

public class ExtensibleRandomValuePropertyNamer : RandomValuePropertyNamer
{
    public IDictionary<Type, Delegate> unknownTypeHandlers = new
Dictionary<Type, Delegate>();

    public ExtensibleRandomValuePropertyNamer NameWith<T>(Func<T> handler) 
    {
        if (unknownTypeHandlers.ContainsKey(typeof(T)))
        {
            unknownTypeHandlers.Remove(typeof (T));
        }
        unknownTypeHandlers.Add(new KeyValuePair<Type, Delegate>(typeof(T),
handler));
        return this;
    }

    protected override void HandleUnknownType<T>(Type memberType, MemberInfo
memberInfo, T obj)
    {
        var handler = GetUnknownTypeHandler(memberType);
        if (handler != null)
        {
            SetValue(memberInfo, obj, handler.DynamicInvoke());
        }
    }

    protected Delegate GetUnknownTypeHandler(Type memberType)
    {
        if (unknownTypeHandlers.ContainsKey(memberType))
        {
            return unknownTypeHandlers[memberType];
        }
        var type = GetTypeWithoutNullability(memberType);
        return unknownTypeHandlers.ContainsKey(type)
            ? unknownTypeHandlers[type]
            : null;
    }

    protected Type GetTypeWithoutNullability(Type type)
    {
        return type.IsGenericType &&
               type.GetGenericTypeDefinition() == typeof(Nullable<>)
            ? new NullableConverter(type).UnderlyingType
            : type;
    }
}

I envision a property namer that uses delegates (instead of hard coded
methods) for all member types (not just unknown types).  The parameterless
c-tor of this class could initialize a dictionary with default handlers for
most CLR types (the same ones that are now hard coded).  Then the user
could swap or remove any of them.  This offers fine grained control of how
the values are set for every type.  We would no longer need ShouldIgnore;
the user can just remove handler for any type.

Here is an example of usage:

var namer = new ExtensibleRandomValuePropertyNamer()
    .NameWith<Address>(AddressBuilder.Build)
    .NameWith<ContactInfo>(ContactInfoBuilder.Build)
    .NameWith(() => PhoneNumber.Parse(GetRandom.PhoneNumber()));
BuilderSetup.SetDefaultPropertyNamer(namer);

Using this approach we can also eliminate the need for minDate and maxDate
fields.  Something like this instead:

namer.NameWith(() => GetRandom.DateTime(new DateTime(2000, 1, 1), new
DateTime(2020, 12, 31)))

Using anonymous delegates in this way the user can exert all kinds of
control over how values are set, without the pains of inheritance.

I would be happy to work on this, but I wanted to show the idea before
making a full blown implementation.

Original issue reported on code.google.com by timtast...@gmail.com on 22 Jun 2009 at 9:34

GoogleCodeExporter commented 8 years ago

Original comment by garethdo...@googlemail.com on 20 Oct 2009 at 8:19

GoogleCodeExporter commented 8 years ago

Original comment by garethdo...@googlemail.com on 20 Oct 2009 at 8:19