Generic Dictionary injection

Aug 2, 2010 at 9:22 PM
Edited Aug 2, 2010 at 9:24 PM

If I have a

TabGroup class with property Tabs of type

Dictionary<string, Tab>

and a TabGroupViewModel class with property Tabs of type

Dictionary<string, TabViewModel>

where TabViewModel has 5 properties (won't write them out here) that are a subset of Tab's properties (same names)

then

TabGroup tabgroup = GetFromDatastore();

TabGroupViewModel model = new TabGroupViewModel();

model.InjectFrom(tabgroup);

works for all TabGroup properties but Dictionary. The Tabs of model object remain null after injection.

If I do this

model.Tabs.InjectFrom(tabgroup.Tabs);

I get NullReferenceException because model.Tabs is null (it is null because the model was just instantiated as new).

Am I doing something that's a bit too much for ValueInjecter or is there something wrong in my code?

Other than that and minor issues (probably only due to the lack of knowledge of VI) I am very happy with VI, works much better than Automapper and it's much more intuitive.

 

Coordinator
Aug 2, 2010 at 9:39 PM
Edited Aug 2, 2010 at 9:40 PM

it's nothing wrong, you're using just the default injection, by doing a.InjectFrom(b) you put the values from props of b to a which are of the same name and type in a and b, the rest are not affected.

so, in your case since Dictionary<string, Tab> and Dictionary<string, TabViewModel> are different types, so you need to create an injection for this; you can do it by extending the LoopValueInjection class (which is actually used by default when you do a.InjectFrom(b))

and after use it

 

a.InjectFrom(b)
  .InjectFrom<YourNewInjection>(b);

 

Coordinator
Aug 3, 2010 at 7:19 AM

so, to be more precise, I think you need something like this:

public class TabsToTabViewModels : LoopValueInjection
    {
        protected override bool TypesMatch(Type sourceType, Type targetType)
        {
            return sourceType == typeof (Dictionary<string, Tab>)
                   && targetType == typeof (Dictionary<string, TabViewModel>);
        }

        protected override object SetValue(object sourcePropertyValue)
        {
            var src = sourcePropertyValue as Dictionary<string, Tab>;
            var trg = new Dictionary<string, TabViewModel>();
            
            // here I'm just playing, cuz I don't know what you need, but it could be something like this
            src.AsParallel().ForAll(o =>
                                        {
                                            var vm = new TabViewModel();
                                            vm.InjectFrom(o.Value);
                                            trg.Add(o.Key, vm);
                                        });

            return trg;
        }
    }

if you don't use .net 4 than just do a simple foreach loop

and the usage:

model.InjectFrom(tabgroup)
.InjectFrom<TabsToTabViewModels>(tabgroup);


you could also override the AllowSetValue in case you want to set the value from src to target in certain conditions, like for example you could check the src for null and return false, so the code in the SetValue is not going to be executed