Search code examples
valueinjecter

Using ValueInjecter, is there a way to only inject a given property one time


Given 3 classes,

A, and B which each have an ID property, and then various other properties

and C, which has an ID, and the combined properties of A and B,

I want to

C.InjectFrom(A);
C.InjectFrom(B);

such that the ID from A is preserved and not overwritten by B.

Obviously in this simple case, I could just reverse the order of the two calls, but in my real world example, it is slightly more complicated where I cannot just solve the problem with ordering.

Esentially I want the second injection to ignore anything that the first injection has already handled, and this may be continued down a chain of several injections. Some of these injections may be from the same objects too

C.InjectFrom(A);
C.InjectFrom<SomeInjector>(A);
C.InjectFrom<SomeInjector2>(A);
C.InjectFrom<SomeInjector3>(A);

etc.


Solution

  • here you go:

    using System;
    using System.Collections.Generic;
    using Omu.ValueInjecter;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                var a = new { Id = 1, P1 = "p1" };
                var b = new { Id = 2, P2 = "p2" };
    
                var c = new C();
    
                var propList = new List<string>();
                c.InjectFrom(new HandlePropOnce(propList), a);
                c.InjectFrom(new HandlePropOnce(propList), b);
    
                Console.WriteLine("Id = {0} P1 = {1} P2 = {2}", c.Id, c.P1, c.P2);
            }
        }
    
        public class C
        {
            public int Id { get; set; }
    
            public string P1 { get; set; }
    
            public string P2 { get; set; }
        }
    
        public class HandlePropOnce : ConventionInjection
        {
            private readonly IList<string> handledProps;
    
            public HandlePropOnce(IList<string> handledProps)
            {
                this.handledProps = handledProps;
            }
    
            protected override bool Match(ConventionInfo c)
            {
                if (handledProps.Contains(c.SourceProp.Name)) return false;
    
                var isMatch = c.SourceProp.Name == c.TargetProp.Name && c.SourceProp.Type == c.TargetProp.Type;
    
                if (isMatch) handledProps.Add(c.SourceProp.Name);
                return isMatch;
            }
        }
    }