Is there another solution for "global" conventions than conventions calling conventions?

Sep 25, 2012 at 10:40 PM

The situation is I have a "FormattedAddress" model that takes its injections from an "Address" type.

FormattedAddress can exist in almost any object.

I want a convention that fills in the FormattedAddress, but needs to support being in a nested hierarchy.

A.B is a "Route"
A.B.C is a "FormattedAddress"

Do I have a RouteConvention, invoked by A.InjectFrom<RouteConvention>(source),
that invokes .InjectFrom<FormattedAddressConvention>(source.B)? This essentially says the route convention calls the formatted address convention when it finds a type of "formattedaddress".

Or, should I make the conventions so that they are chained in the first invoke, and the order matters. I would also have to custom write all of the matching code etc, because value injecter does not do deep matching by default.

ie:
A.InjectFrom<RouteConvention>(source) // fills in the route object (B) but leaves C null
A.InjectFrom<FormattedAddressConvention>(source) // deep clone to find A.B.C

Any thoughts/opinions? I was unable to find any examples of this. 

Sep 27, 2012 at 7:47 PM

probably the DeepClone injection will be a good start: http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home

Sep 28, 2012 at 5:39 PM

So that deep clone seems to use nested injections.

So then nested injections are something that is intended?

None of my types are matching besides basic CLR types.

I am translating our domain to our model objects inside a facade layer.

So:

Listing -> ListingModel, etc.

So far what I have decided to go with is a custom "ModelConvention" that matches anything where name matches, and the target type starts with the source type name, and the types do not match.

I used a convention injection, and then changed the inject method to not access .Value until a match has been made (passes null as value to Match)

Then I do this:


        protected override object SetValue(ConventionInfo c)
        {
            if (c.SourceProp.Value == null)
                return null;

            if (typeof(IEnumerable).IsAssignableFrom(c.TargetProp.Type))
            {
                //var sourceItemType = c.SourceProp.Type.GetGenericArguments().First();
                var targetItemType = c.TargetProp.Type.GetGenericArguments().First();
                var listType = typeof(List<>).MakeGenericType(targetItemType);

                var targetList = Activator.CreateInstance(listType);
                var addMethod = targetList.GetType().GetMethod("Add");
                foreach (var x in (IEnumerable)c.SourceProp.Value)
                {
                    var item = Activator.CreateInstance(targetItemType);
                    item.InjectFrom<ModelConvention>(x);
                    item.InjectFrom(x);
                    item.InjectFrom<PartialInjection>(x);

                    addMethod.Invoke(targetList, new[] { item });
                }
                return targetList;
            }

            var target = Activator.CreateInstance(c.TargetProp.Type);

            target.InjectFrom<ModelConvention>(c.SourceProp.Value);
            target.InjectFrom(c.SourceProp.Value);
            target.InjectFrom<PartialInjection>(c.SourceProp.Value);
            return target;
        }

The partial injection, is a value injection that acts like a factory.
It searches for any ValueInjection that inherits from PartialValueInjection<TSource, TTarget> : ValueInjection
The point was, that the model injection will fill in "most" properties. Then if you have custom work to do on the object, you create a
 ValueInjection that looks like:

ListingModelValueInjection : PartialValueInjection<Listing, ListingModel>
{
public override void Inject(Listing source, ListingModel target)
{
target.Bar = source.Foo; // special cases
}

Sep 28, 2012 at 6:42 PM

nested injections in the deep clone is basically the injection calling itself for reference types

and for collections it creates a collection and applies itself to each new object it creates

about the .Value, you could inherit the SmartConventionValueInjection instead of Convention to make it faster http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection&referringTitle=Home