Reputation: 155
I have three libraries, each containing a namespace for models, and all the models in each library are effectively identical in the data they hold--they have minor differences in how they are implemented, but I don't have control over that as the code is auto-generated.
I need to adapt one model to the other quite often, and to do this I am using Mapster. When the models are simple, this can be as simple as this:
var libraryBObject = LibraryA.Models.AnObject.Adapt<LibraryB.Models.AnObject>();
If the model gets more complex, you need to specify a mapping like so:
public static void Configure() {
var config = TypeAdapterConfig.GlobalSettings;
config.NewConfig<LibraryA.Models.AnObject, LibraryB.Models.AnObject>()
.MapWith(src => new LibraryB.Models.AnObject(src.Prop1, src.Prop2));
}
And to complicate matters further, the models in one library DO NOT have constructors so you have to set the fields like this:
public static void Configure() {
var config = TypeAdapterConfig.GlobalSettings;
config.NewConfig<LibraryA.Models.AnObject, LibraryB.Models.AnObject>()
.MapWith(src => new LibraryB.Models.AnObject(){ Prop1 = src.Prop1, Prop2 = src.Prop2 });
}
There are quite a few models, and I am occasionally updating models as well, which makes this somewhat tedious to maintain.
Is there a way to use reflection to iterate through the models in each namespace and create the mapping automatically?
Thanks in advance!
Upvotes: 0
Views: 217
Reputation: 107
Do you mean something like this? I've created it for my program to get desired parsing method by user in runtime. Perhaps you would need to change executing assembly to yours instead:
public static class Reflection
{
public static List<string> GetCertainClass(string nameSpaceName)
{
var currentAsmembly = Assembly.GetExecutingAssembly().GetTypes();
var listOfClasses = new List<string>();
foreach (var type in currentAsmembly)
{
if (type != null
&& type.IsClass
&& type.IsGenericType == false
&& type.FullName?
.Contains(nameSpaceName, StringComparison.InvariantCultureIgnoreCase) == true
&& type.Namespace?
.Contains(nameSpaceName, StringComparison.InvariantCultureIgnoreCase) == true
&& type.Name
.Contains(nameSpaceName, StringComparison.InvariantCultureIgnoreCase))
{
listOfClasses.Add(type.FullName);
}
}
if (listOfClasses.Count == 0)
throw new ClassInitializationException(
@$"No classes contain ""{nameSpaceName}"" in their names " +
@$"and/or classes are not placed in a namespace that " +
@$"contains ""{nameSpaceName}"".");
return listOfClasses;
}
public static T GetCertainParsingMethod<T>
(string selectedParsingClass, string methodName, string secondMethodName = "")
{
var type = Type.GetType(selectedParsingClass);
var GetDataFromMethod = type?.GetMethod(methodName);
if (GetDataFromMethod == null)
{
throw new ArgumentNullException(nameof(GetDataFromMethod),
"No methods found to be invoked");
}
else
{
if (GetDataFromMethod.GetParameters().Length == 0)
{
return (T)GetDataFromMethod.Invoke(null, null)!;
}
else
{
return (T)GetDataFromMethod.Invoke(null, new object[] { secondMethodName })!;
}
}
}
}
First you get list of classes in a namespace, e.g.:
List<string> parsingClasees = Reflection.GetCertainClass("parse");
// string selectedClass from the List<string>
Then you can execute a method in that class:
var resultFromFirstMethod = Reflection
.GetCertainParsingMethod<List<string>>(selectedClass, firstMethodName);
The optional parameter is a name of another method that I executed afterwards
var resultFromSecondMethod = Reflection
.GetCertainParsingMethod<List<List<object>>>(selectedParsingClass, secondMethodName, resultFromFirstMethod);
Upvotes: 0