I'm working on the upgrade of an application from net framework to .net core 3.0. I am using windows presentation foundation Wpf and I want to implement ValueInjecter in its last version 3.2... The application is currently running on version 2.4 of ValueInjecter help please!. There is not much documentation on the web. How would this code look? My CloneInjection.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Omu.ValueInjecter;
namespace Infrastructure.Data.Injection
{
public class CloneInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name && c.SourceProp.Value != null;
}
protected override object SetValue(ConventionInfo c)
{
//for value types and string just return the value as is
if (c.SourceProp.Type.IsValueType || c.SourceProp.Type == typeof(string))
return c.SourceProp.Value;
//handle arrays
if (c.SourceProp.Type.IsArray)
{
var arr = c.SourceProp.Value as Array;
var clone = arr.Clone() as Array;
for (int index = 0; index < arr.Length; index++)
{
var a = arr.GetValue(index);
if (a.GetType().IsValueType || a is string) continue;
clone.SetValue(Activator.CreateInstance(a.GetType()).InjectFrom<CloneInjection>(a), index);
}
return clone;
}
if (c.SourceProp.Type.IsGenericType)
{
//handle IEnumerable<> also ICollection<> IList<> List<>
if (c.SourceProp.Type.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)))
{
var t = c.SourceProp.Type.GetGenericArguments()[0];
if (t.IsValueType || t == typeof(string)) return c.SourceProp.Value;
var tlist = typeof(List<>).MakeGenericType(t);
var list = Activator.CreateInstance(tlist);
var addMethod = tlist.GetMethod("Add");
foreach (var o in c.SourceProp.Value as IEnumerable)
{
var e = Activator.CreateInstance(t).InjectFrom<CloneInjection>(o);
addMethod.Invoke(list, new[] { e }); // in 4.0 you can use dynamic and just do list.Add(e);
}
return list;
}
//unhandled generic type, you could also return null or throw
return c.SourceProp.Value;
}
//for simple object types create a new instace and apply the clone injection on it
return Activator.CreateInstance(c.SourceProp.Type)
.InjectFrom<CloneInjection>(c.SourceProp.Value);
}
}
}
My EntityInjection.cs:
using System.Collections;
using System.Diagnostics;
using System.Linq;
using Omu.ValueInjecter;
namespace Infrastructure.Data.Injection
{
public class EntityInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
var propertyMatch = c.SourceProp.Name == c.TargetProp.Name;
var sourceNotNull = c.SourceProp.Value != null;
bool targetPropertyIdWritable = !(propertyMatch && c.TargetProp.Name == "Id" && !(c.Target.Value is IEntityClass));
return propertyMatch && sourceNotNull && targetPropertyIdWritable;
}
protected override object SetValue(ConventionInfo c)
{
if (c.SourceProp.Type.IsValueType || c.SourceProp.Type == typeof(string))
return c.SourceProp.Value;
if (c.SourceProp.Type.IsGenericType)
{
var td = c.SourceProp.Type.GetGenericTypeDefinition();
if (td != null && td.GetInterfaces().Contains(typeof(IEnumerable)))
{
var targetChildType = c.TargetProp.Type.GetGenericArguments()[0];
if (targetChildType.IsValueType || targetChildType == typeof(string)) return c.SourceProp.Value;
if (targetChildType.GetInterfaces().Any(x => x == typeof(IValueClass)))
{
var deleteMethod = c.TargetProp.Value.GetType().GetMethod("Remove");
var rmvItems = (c.TargetProp.Value as IEnumerable).Cast<IValueClass>()
.Where(x => x.Id > 0 && !(c.SourceProp.Value as IEnumerable).Cast<IValueClass>().Any(y => y.Id == x.Id));
rmvItems.ToList().ForEach(x => deleteMethod.Invoke(c.TargetProp.Value, new[] { x }));
rmvItems = (c.TargetProp.Value as IEnumerable).Cast<IValueClass>()
.Where(x => !(c.SourceProp.Value as IEnumerable).Cast<IValueClass>().Contains(x));
rmvItems.ToList().ForEach(x => deleteMethod.Invoke(c.TargetProp.Value, new[] { x }));
var sourceCollection = (c.SourceProp.Value as IEnumerable).Cast<IValueClass>();
foreach (var s in sourceCollection)
{
var sv = s;
var target = (c.TargetProp.Value as IEnumerable).Cast<IValueClass>().SingleOrDefault(z => z.Id == sv.Id && z.Id != 0);
if (target != null) target.InjectFrom<EntityInjection>(sv);
else if (!(c.TargetProp.Value as IEnumerable).Cast<IValueClass>().Contains(sv))
{
if (!(sv is IEntityClass))
{
sv = Activator.CreateInstance(targetChildType) as IValueClass;
Debug.Assert(sv != null);
sv.InjectFrom<EntityInjection>(s);
sv.Id = 0;
}
var addMethod = c.TargetProp.Value.GetType().GetMethod("Add");
addMethod.Invoke(c.TargetProp.Value, new[] { sv });
}
}
}
}
return c.TargetProp.Value;
}
if (c.SourceProp.Value is IEntityClass)
{
return c.SourceProp.Value;
}
if (c.TargetProp.Value == null)
{
try
{
c.TargetProp.Value = Activator.CreateInstance(c.TargetProp.Type);
}
catch (Exception)
{
return null;
}
}
return c.TargetProp.Value.InjectFrom<EntityInjection>(c.SourceProp.Value);
}
}
}
if you can't switch to LoopInjection
you could also try to add this class into your project:
public abstract class ConventionInjection : ValueInjection
{
protected abstract bool Match(ConventionInfo c);
protected virtual object SetValue(ConventionInfo c)
{
return c.SourceProp.Value;
}
protected override void Inject(object source, object target)
{
var sourceProps = source.GetProps();
var targetProps = target.GetProps();
var ci = new ConventionInfo
{
Source =
{
Type = source.GetType(),
Value = source
},
Target =
{
Type = target.GetType(),
Value = target
}
};
for (var i = 0; i < sourceProps.Count; i++)
{
var s = sourceProps[i];
ci.SourceProp.Name = s.Name;
ci.SourceProp.Value = s.GetValue(source);
ci.SourceProp.Type = s.PropertyType;
for(var j=0; j < targetProps.Count; j++)
{
var t = targetProps[j];
ci.TargetProp.Name = t.Name;
ci.TargetProp.Value = t.GetValue(target);
ci.TargetProp.Type = t.PropertyType;
if (Match(ci))
t.SetValue(target, SetValue(ci));
}
}
}
}
public class ConventionInfo
{
public ConventionInfo()
{
Source = new TypeInfo();
Target = new TypeInfo();
SourceProp = new PropInfo();
TargetProp = new PropInfo();
}
public TypeInfo Source { get; set; }
public TypeInfo Target { get; set; }
public PropInfo SourceProp { get; set; }
public PropInfo TargetProp { get; set; }
public class PropInfo
{
public string Name { get; set; }
public Type Type { get; set; }
public object Value { get; set; }
}
public class TypeInfo
{
public Type Type { get; set; }
public object Value { get; set; }
}
}