/// <summary> /// Loads exported types from a given assembly /// </summary> /// <param name="assembly">The assembly to search for exported types</param> /// <param name="signedOnly">Only load exported types from this assembly if the assembly has been digitally signed</param> /// <param name="actionIfUnsigned">If only signed assemblies should be loaded, and this assembly is not signed, load /// exported types nonetheless if this action returns true</param> public static void LoadExports(Assembly assembly, bool signedOnly = false, Func <Assembly, bool> actionIfUnsigned = null) { if (signedOnly) { try { X509Certificate.CreateFromSignedFile(assembly.Location); } catch (CryptographicException e) { if (actionIfUnsigned == null || !actionIfUnsigned(assembly)) { return; } } } foreach (var type in assembly.GetExportedTypes()) { var custom = type.GetCustomAttributes(); foreach (var attrib in custom) { switch (attrib) { case ExportAttribute ea: ExportedTypes.Add(new ExportedType(type, ea.ExportedType, false)); break; case ExportManyAttribute ema: ExportedTypes.Add(new ExportedType(type, ema.ExportedType, true)); break; } } } }
public static void AddExportedType(Type actualType, Type exportedAsType, bool exportMany = false) { if (ExportedTypes.Any(x => x.ExposedType == exportedAsType)) { throw new Exception($"Type {exportedAsType.FullName} has already been exported"); } ExportedTypes.Add(new ExportedType(actualType, exportedAsType, exportMany)); }
/// <summary> /// read data from DTO back to POCO. /// NOTE: does not manage array / enumerations as yet /// </summary> /// <param name="code"></param> private void GenerateReadFromDTO(StringBuilder code) { code.IndentLine(2, $"public static {_poco.Name} ReadFromDTO({_poco.Name} target, {_poco.Name}DTO source)"); code.IndentLine(2, "{"); foreach (Tuple <MemberInfo, MemberInfo> item in _members) { MemberInfo member = item.Item1; Type memberType = GetDataType(member); MemberInfo sibling = item.Item2; if (memberType.IsArray && memberType != typeof(string)) { Type elementType = memberType.GetElementType(); if (elementType != null) { // use TX for exported type to deep copy if (ExportedTypes.Contains(elementType)) { code.IndentLine(3, $"target.{member.Name} = source.{ConflateType(sibling)}{member.Name}.Select({elementType}TX.WriteToDTO).ToArray(),"); } else { code.IndentLine(3, $"target.{member.Name} = source.{ConflateType(sibling)}{member.Name}.Select().ToArray(),"); } } } else if (!memberType.IsArray && memberType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(memberType)) { code.IndentLine(3, $"Read{member.Name}FromDTO(target.{ConflateType(sibling)}{member.Name}, source.{member.Name});"); } else if (ExportedTypes.Contains(memberType)) { code.IndentLine(3, $"{memberType.Name}TX.ReadFromDTO(target.{ConflateType(sibling)}{member.Name}, source.{member.Name});"); } else { code.IndentLine(3, $"target.{ConflateType(sibling)}{member.Name} = source.{member.Name};"); } } code.IndentLine(3, "return target;"); code.IndentLine(2, "}"); code.AppendLine(); // write methods to copy colections foreach (Tuple <MemberInfo, MemberInfo> item in _members) { MemberInfo member = item.Item1; Type memberType = GetDataType(member); if (!memberType.IsArray && memberType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(memberType)) { GenerateCopyCollection(code, member); } } }
/// <summary> /// convert existing class reference to equiv DTO for non conflated members /// </summary> /// <param name="type"></param> /// <returns></returns> private string ConvertToDTOType(Type type) { if (ExportedTypes.Contains(type)) { return(type.Name + "DTO"); } return(CleanTypeName(type)); }
/// <summary> /// convert c# type to TS /// </summary> /// <param name="type"></param> /// <returns></returns> private string ConvertToTsType(Type type) { while (true) { if (type != null && type.IsPrimitive) { if (type == typeof(bool)) { return("boolean"); } return(type == typeof(char) ? "string" : "number"); } if (type == typeof(decimal)) { return("number"); } if (type == typeof(string)) { return("string"); } if (type != null && type.IsArray) { Type at = type.GetElementType(); return(ConvertToTsType(at) + "[]"); } if (typeof(IEnumerable).IsAssignableFrom(type)) { if (type != null) { Type collectionType = type.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument return(ConvertToTsType(collectionType) + "[]"); } } if (type != null && Nullable.GetUnderlyingType(type) != null) { type = Nullable.GetUnderlyingType(type); continue; } if (type != null && type.IsEnum) { return("number"); } if (type != null) { return(ExportedTypes.Contains(type) ? type.Name : "any"); } } }
public void Execute() { bool refresh = false; for (int i = 0; i < newTypeNodeCreators.Length; i++) { newTypeNodeCreators[i].Add(); } for (int i = 0; i < existingTypeNodeUpdaters.Length; i++) { existingTypeNodeUpdaters[i].Add(); } if (origAssemblyDeclSecurities is not null && newAssemblyDeclSecurities is not null) { modNode.Document.AssemblyDef !.DeclSecurities.Clear(); foreach (var ds in newAssemblyDeclSecurities) { modNode.Document.AssemblyDef.DeclSecurities.Add(ds); } } if (origAssemblyCustomAttributes is not null && newAssemblyCustomAttributes is not null) { modNode.Document.AssemblyDef !.CustomAttributes.Clear(); foreach (var ca in newAssemblyCustomAttributes) { modNode.Document.AssemblyDef.CustomAttributes.Add(ca); } } if (origModuleCustomAttributes is not null && newModuleCustomAttributes is not null) { modNode.Document.ModuleDef !.CustomAttributes.Clear(); foreach (var ca in newModuleCustomAttributes) { modNode.Document.ModuleDef.CustomAttributes.Add(ca); } } if (origExportedTypes is not null && newExportedTypes is not null) { modNode.Document.ModuleDef !.ExportedTypes.Clear(); foreach (var et in newExportedTypes) { modNode.Document.ModuleDef.ExportedTypes.Add(et); } } if (newAssemblyVersion is not null && origAssemblyVersion is not null) { modNode.Document.AssemblyDef !.Version = newAssemblyVersion; refresh = true; } resourceNodeCreator?.Add(); if (refresh) { asmNode?.TreeNode.RefreshUI(); } }
public static object CreateAndCompose(Type type, params object[] nonComposedParams) { var nonComposedParamsList = nonComposedParams.ToList(); var constructor = type.GetConstructors().FirstOrDefault(x => x.IsPublic); if (constructor == null) { throw new NullReferenceException($"Type {type.FullName} contains no public constructor"); } var constructorArgs = new List <object>(); var i = 0; foreach (var prmInfo in constructor.GetParameters()) { var prm = nonComposedParamsList.FirstOrDefault(x => x.GetType() == prmInfo.ParameterType); if (prm == null) { foreach (var p in nonComposedParams) { var pt = p.GetType(); var interfaces = pt.GetInterfaces(); if (interfaces.Any(x => x == prmInfo.ParameterType)) { prm = p; break; } } } if (prm != null) { nonComposedParamsList.Remove(prm); constructorArgs.Add(prm); } else if (prmInfo.ParameterType.IsInterface) { var singletonType = ExportedTypes.FirstOrDefault(x => x.ExposedType == prmInfo.ParameterType)?.ActualType; if (singletonType == null) { throw new NullReferenceException($"No type {prmInfo.ParameterType.FullName} could be matched with any exported type"); } var singleton = GetSingleton(singletonType); constructorArgs.Add(singleton); } else { throw new Exception($"Found no matching argument for parameter {prmInfo.Name} in constructor for type {type.FullName}"); } } var o = constructor.Invoke(constructorArgs.ToArray()); Compose(o); return(o); }
/// <summary> /// Tries to find/identify a <see cref="Type"/> by its name /// </summary> /// <param name="typeName">The name of the <see cref="Type"/></param> /// <returns>The <see cref="Type"/> that is defined by the parameter <paramref name="typeName"/></returns> /// <exception cref="ArgumentNullException"> /// The <paramref name="typeName"/> parameter is null /// </exception> /// <exception cref="ArgumentException"> /// The <paramref name="typeName"/> parameter is an empty string /// </exception> public static Type GetTypeFromName(string typeName) { if (typeName == null) { throw new ArgumentNullException(nameof(typeName)); } if (typeName.Length == 0) { throw new ArgumentException("The parameter is an empty string", nameof(typeName)); } var result = ExportedTypes .FirstOrDefault(x => x.FullName != null && x.FullName.GetHashCode() == typeName.GetHashCode() && x.FullName == typeName); if (result != null) { return(result); } // Maybe the type is just a part of the type name... result = ExportedTypes.FirstOrDefault(x => x.FullName != null && x.Name.EndsWith(typeName)); if (result != null) { return(result); } // Else let us loop through all known assemblies and look for the type for (int i = 0; i < _assemblies.Count; i++) { var type = _assemblies[i].GetType(typeName); if (type != null) { return(type); } } // The last resort result = Type.GetType(typeName); if (result != null) { return(result); } Output.WriteLineError($"The type '{typeName}' defined by the parameter 'typeName' was not found"); return(null); }
/// <summary> /// read through members and build a list, conflating as appropriate /// </summary> /// <param name="target"></param> /// <param name="sibling"></param> private void AnalyseFields(Type target, MemberInfo sibling) { // scan through properties and fields of target type // if this is the main class then do not check for existing fields foreach (MemberInfo member in GetMembers(target)) { // do we already have this field (or is it part of parent // and we are going to deal with it later)? if (sibling != null && _existingMembers.Any(mi => mi.Name == member.Name)) { Log.AppendLine($" field '{member.Name}' ignored as it already exists;"); continue; } // ReSharper disable once SwitchStatementMissingSomeCases (we are not interested in other member types) switch (member.MemberType) { case MemberTypes.Field: // short cut field FieldInfo fieldInfo = (FieldInfo)member; // see if this is a sibling object if (ExportedTypes.Contains(fieldInfo.FieldType) && IsConflated(member)) { AnalyseFields(fieldInfo.FieldType, member); continue; } break; case MemberTypes.Property: // short cut field PropertyInfo propertyInfo = (PropertyInfo)member; // see if this is a sibling object if (ExportedTypes.Contains(propertyInfo.PropertyType) && IsConflated(member)) { AnalyseFields(propertyInfo.PropertyType, member); continue; } break; default: continue; } _members.Add(new Tuple <MemberInfo, MemberInfo>(member, sibling)); } }
internal static IList <MethodInfo> FindConfigurationMethods(IEnumerable <Assembly> configurationAssemblies, Type configType) { return(configurationAssemblies .SelectMany(a => a. #if NET40 GetExportedTypes() #else ExportedTypes #endif .Select(t => t.GetTypeInfo()).Where(t => t.IsSealed && t.IsAbstract && !t.IsNested)) .SelectMany(t => t.DeclaredMethods) .Where(m => m.IsStatic && m.IsPublic && m.IsDefined(typeof(ExtensionAttribute), false)) .Where(m => m.GetParameters()[0].ParameterType == configType) .ToList()); }
public static object GetExportedTypeInstance(Type type) { var t = ExportedTypes.FirstOrDefault(x => x.ExposedType == type); if (t == null) { throw new NullReferenceException($"No type {type.FullName} has been exported"); } switch (t.Many) { case true: return(CreateAndCompose(t.ActualType)); default: return(GetSingleton(t.ActualType)); } }
public void CopyTo(Module copy) { copy._name = _name; copy._mvid = _mvid; copy._frameworkVersionMoniker = _frameworkVersionMoniker; copy._entryPoint = EntryPoint; AssemblyReferences.CopyTo(copy.AssemblyReferences); ModuleReferences.CopyTo(copy.ModuleReferences); Files.CopyTo(copy.Files); Types.CopyTo(copy.Types); ExportedTypes.CopyTo(copy.ExportedTypes); Resources.CopyTo(copy.Resources); CustomAttributes.CopyTo(copy.CustomAttributes); if (_unmanagedResources != null) { copy._unmanagedResources = _unmanagedResources.Clone(); } }
/// <summary> /// Compose an object: all properties of the object decorated with an /// Import or ImportMany attribute, will be instantiated accordingly. /// Alternatively, if a Type if provided, it will be scanned for public /// static properties marked for import. /// </summary> /// <param name="root">The object to compose, or a type if composing must be done for static properties of a class</param> public static void Compose(object root) { if (root == null) { return; } PropertyInfo[] infos; object obj; if (root is Type rootType) { obj = null; infos = rootType.GetProperties( BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); } else { obj = root; infos = root.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); } foreach (var prop in infos) { var browsable = prop.GetCustomAttribute <BrowsableAttribute>(); if (browsable != null && !browsable.Browsable) { continue; } var attribs = prop.GetCustomAttributes().ToArray(); if (attribs.Length == 0 && !prop.PropertyType.IsValueType && prop.PropertyType != typeof(string)) { // Recursive composition is only allowed for generic types for now if (prop.PropertyType.IsGenericType) { Compose(prop.GetValue(root)); } } foreach (var attrib in attribs) { ExportedType[] exportedTypes; switch (attrib) { case ImportAttribute ia: exportedTypes = ExportedTypes.Where(x => x.ExposedType == prop.PropertyType).ToArray(); if (exportedTypes.Length == 0) { throw new Exception($"No exported type matched imported type {prop.PropertyType.FullName}"); } if (exportedTypes.Length > 1) { throw new AmbiguousMatchException($"More than one exported types match imported type {prop.PropertyType.FullName}"); } object instance; switch (exportedTypes[0].Many) { case true: instance = CreateAndCompose(exportedTypes[0].ActualType); break; default: instance = GetSingleton(exportedTypes[0].ActualType); break; } prop.SetValue(obj, instance); break; case ImportManyAttribute ima: if (!prop.PropertyType.IsGenericType) { throw new Exception("ImportMany can only be applied on generic types"); } exportedTypes = ExportedTypes.Where(x => x.ExposedType == ima.ImportedType).ToArray(); var constructedListType = typeof(List <>).MakeGenericType(ima.ImportedType); var instanceList = (IList)Activator.CreateInstance(constructedListType); foreach (var t in exportedTypes) { var listItem = instance = CreateAndCompose(t.ActualType); instanceList.Add(listItem); } try { prop.SetValue(obj, instanceList); } catch (ArgumentException) { throw new Exception("No setter found for property " + prop.Name + ", or wrong type"); } break; } } } }
/// <summary> /// copy data from POCO to new DTO and manage conflation /// </summary> /// <param name="code"></param> private void GenerateWriteToDTO(StringBuilder code) { code.IndentLine(2, $"public static {_poco.Name}DTO WriteToDTO({_poco.Name} source)"); code.IndentLine(2, "{"); code.IndentLine(3, $"return new {_poco.Name}DTO"); code.IndentLine(4, "{"); foreach (Tuple <MemberInfo, MemberInfo> item in _members) { MemberInfo member = item.Item1; Type memberType = GetDataType(member); MemberInfo sibling = item.Item2; if (memberType.IsArray) { Type elementType = memberType.GetElementType(); if (elementType != null) { // use TX for exported type to deep copy if (ExportedTypes.Contains(elementType)) { code.IndentLine(5, $"{member.Name} = source.{ConflateType(sibling)}{member.Name}.Select({elementType}TX.WriteToDTO).ToArray(),"); } else { code.IndentLine(5, $"{member.Name} = source.{ConflateType(sibling)}{member.Name}.Select().ToArray(),"); } continue; } } if (memberType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(memberType)) { // use TX for exported type to deep copy MemberInfo elementType = memberType.GetGenericArguments()[0]; if (ExportedTypes.Contains(elementType)) { code.IndentLine(5, $"{member.Name} = source.{ConflateType(sibling)}{member.Name}.Select({elementType.Name}TX.WriteToDTO).ToArray(),"); } else { code.IndentLine(5, $"{member.Name} = source.{ConflateType(sibling)}{member.Name}.Select().ToArray()"); } continue; } if (ExportedTypes.Contains(memberType)) { code.IndentLine(5, $"{member.Name} = {ConflateType(sibling)}{member.Name}TX.WriteToDTO(source.{member.Name}),"); } else { code.IndentLine(5, $"{member.Name} = source.{ConflateType(sibling)}{member.Name},"); } } code.IndentLine(4, "};"); code.IndentLine(2, "}"); code.AppendLine(""); }