using System.Collections.Generic;
public class NullValueDictionary<T, U> : Dictionary<T, U> where U : class
new public U? this[T key] {
this.TryGetValue(key, out var val);
public abstract class ShadowOM {
protected abstract Type ModelType { get; }
public String Type() => ModelType.Name;
public dynamic Root() => Convert.ChangeType(this, ModelType);
public T To<T>() => (T) Convert.ChangeType(this, typeof(T));
public bool Is(Type type) => type == ModelType;
public bool Has(String prop) => this.GetType().GetProperty(prop) != null;
public NullValueDictionary<Type, dynamic> In(Type[] list) =>
list.Where(x => Is(x)).ToList().Any() ?
new NullValueDictionary<Type, dynamic> {{
list.Where(x => Is(x)).Single(),
new Func<dynamic>(() => {
var properties = root.GetType().GetProperties();
var instance = Activator.CreateInstance(list.Where(x => Is(x)).Single());
var writeReadProps = ((IEnumerable<dynamic>)properties).Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in writeReadProps) {
object copyValue = prop.GetValue(root);
prop.SetValue(instance, copyValue);
}} : new NullValueDictionary<Type, dynamic>();
public class Type1 : ShadowOM {
sealed protected override Type ModelType { get; } = typeof(Type1);
public string Prefix { get; } = "1";
public string? Name { get; init; }
public class Type2 : ShadowOM {
sealed protected override Type ModelType { get; } = typeof(Type2);
public string Prefix { get; } = "2";
public string? Name { get; init; }
public string? Suffix { get; init; }
public static void Main() {
var t1 = new Type1 { Name = "Name1" };
var t2 = new Type2 { Name = "Name2", Suffix = "Ext" };
ShadowOM[] shadows = new [] { (t1 as ShadowOM), (t2 as ShadowOM) };
List<dynamic> roots = shadows.Select(m => m.Root()).ToList();
var types = shadows.Select(m => m.Type());
var names = roots.Select(m => m.Name);
dynamic t1Root = roots[0], t2Root = roots[1];
Console.WriteLine(types.Aggregate((i, j) => i + "," + j));
Console.WriteLine(names.Aggregate((i, j) => i + "," + j));
@file {t1Root.Prefix}_{t1Root.Name}_{(t1Root.Has("Suffix") ? t1Root.Suffix + "_" : "")}Info.log
@brief This file contains general information.
Warning! This is a generated file. Manual changes will be omitted.
@file {t2Root.Prefix}_{t2Root.Name}_{(t2Root.Has("Suffix") ? t2Root.Suffix + "_" : "")}Info.log
@brief This file contains general information.
Warning! This is a generated file. Manual changes will be omitted.
Type type1 = typeof(Type1), type2 = typeof(Type2);
t1OM = model1.To<Type1>();
} catch (InvalidCastException) {
var nvdModelSet = model2.In(new [] { type1, type2 });
if (!nvdModelSet.Values.Any(x => x != null))
Type2? t2OM = nvdModelSet[type2];
@file {t1OM.Prefix}_{t1OM.Name}_Info.log
@brief This file contains general information.
Warning! This is a generated file. Manual changes will be omitted.
@file {t2OM.Prefix}_{t2OM.Name}_{t2OM.Suffix}_Info.log
@brief This file contains general information.
Warning! This is a generated file. Manual changes will be omitted.
if (model2.Is(type2) && t2OM != null) {
@file {t2OM.Prefix}_{t2OM.Name}_{t2OM.Suffix}_Info.log
@brief This file contains general information.
Warning! This is a generated file. Manual changes will be omitted.