关于使用工厂模式将模型对象集合转换为 DTO 之一的建议,反之亦然
Advice on using the Factory Pattern for converting a collection of model objects to one of DTOs and vice versa
我正在尝试将共享一个公共父对象的模型对象集合转换为一个 DTO。同样,我想反转该过程 - 将具有共同父对象的一组 DTO 放入一个模型对象中。
根据我的阅读,工厂模式似乎正是我正在寻找的。我还有一个 Producer class,它通过调用相关的工厂方法来处理对象模型和 DTO 之间的转换。
有一些限制:
- 这是一个开源库,我不想向现有的 class 添加方法。否则访问者模式就会起作用。如有错误请指正
- 同样,我不想向这个项目添加任何额外的包。据我了解,AutoMapper 可能是解决此问题的方法之一。
- 我是 C# 和设计模式的新手,所以如果我做的事情没有意义,我深表歉意。
这里是一些示例代码,代表了我到目前为止所做的尝试。我使用了网上的一些参考来获得一个想法,但它似乎有些不对。这里提到了另一种方式:Is a switch statement applicable in a factory method? c#,但我不确定这是否适用于这种情况。
欢迎任何批评或建议。
用法示例
Animal pet1 = new Pigeon("Pidgey", 100, false);
Animal pet2 = new Rattlesnake("Ekans", 20.0, true);
IList<Animal> myPets = new List<Animal>() { pet1, pet2 };
AnimalDTOProducer dtoProducer = new AnimalDTOProducer(new AnimalDTOFactory());
IList<AnimalDTO> myDTOs = new List<AnimalDTO>();
myDTOs = dtoProducer.ConvertAnimalCollection(myPets);
型号
public abstract class Animal
{
public Animal(string name)
{
Name = name;
}
public string Name { get; set; }
// business logic
}
public abstract class Bird : Animal
{
public Bird(string name, int maxAltitude, bool isReal)
: base(name)
{
Name = name;
MaxAltitude = maxAltitude;
IsReal = isReal;
}
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
// business logic
}
public class Pigeon : Bird
{
public Pigeon(string name, int maxAltitude, bool isReal)
: base(name, maxAltitude, isReal)
{
}
// business logic
}
public abstract class Snake : Animal
{
public Snake(string name, double length, bool isPoisonous)
: base(name)
{
Name = name;
Length = length;
IsPoisonous = isPoisonous;
}
public double Length { get; set; }
public bool IsPoisonous { get; set; }
// business logic
}
public class Rattlesnake : Snake
{
public Rattlesnake(string name, double length, bool isPoisonous)
: base(name, length, isPoisonous)
{
}
// business logic
}
DTOs
public abstract class AnimalDTO { }
public class PigeonDTO : AnimalDTO
{
public string Name { get; set; }
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
}
public class RattlesnakeDTO : AnimalDTO
{
public string Name { get; set; }
public double Length { get; set; }
public bool IsPoisonous { get; set; }
}
工厂
public interface IFactory { }
public interface IAnimalFactory : IFactory
{
Animal CreateAnimal(AnimalDTO DTO);
}
public interface IAnimalDTOFactory : IFactory
{
AnimalDTO CreateAnimalDTO(Animal animal);
}
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
switch (DTO)
{
case PigeonDTO _:
var pigeonDTO = (PigeonDTO)DTO;
return new Pigeon(pigeonDTO.Name, pigeonDTO.MaxAltitude, pigeonDTO.IsReal);
case RattlesnakeDTO _:
var rattlesnakeDTO = (RattlesnakeDTO)DTO;
return new Rattlesnake(rattlesnakeDTO.Name, rattlesnakeDTO.Length, rattlesnakeDTO.IsPoisonous);
// And many more ...
default:
return null;
}
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
switch (animal)
{
case Pigeon _:
var _pigeon = (Pigeon)animal;
return new PigeonDTO()
{
Name = _pigeon.Name,
MaxAltitude = _pigeon.MaxAltitude,
IsReal = _pigeon.IsReal
};
case Rattlesnake _:
var _rattlesnake = (Rattlesnake)animal;
return new RattlesnakeDTO()
{
Name = _rattlesnake.Name,
Length = _rattlesnake.Length,
IsPoisonous = _rattlesnake.IsPoisonous
};
// And many more ...
default:
return null;
}
}
}
生产者
public interface IProducer { }
public interface IAnimalProducer : IProducer
{
Animal ProduceAnimalFromDTO(AnimalDTO DTO);
}
public interface IAnimalDTOProducer : IProducer
{
AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal);
}
public class AnimalProducer : IAnimalProducer
{
private IAnimalFactory factory;
public AnimalProducer(IAnimalFactory factory)
{
this.factory = factory;
}
public IList<Animal> ConvertAnimalDTOCollection(IList<AnimalDTO> DTOCollection)
{
IList<Animal> result = new List<Animal>();
foreach (AnimalDTO DTO in DTOCollection)
{
var dto = ProduceAnimalFromDTO(DTO);
if (dto != null)
result.Add(dto);
}
return result;
}
public Animal ProduceAnimalFromDTO(AnimalDTO animalDTO)
{
return this.factory.CreateAnimal(animalDTO);
}
}
public class AnimalDTOProducer : IAnimalDTOProducer
{
private IAnimalDTOFactory factory;
public AnimalDTOProducer(IAnimalDTOFactory factory)
{
this.factory = factory;
}
public IList<AnimalDTO> ConvertAnimalCollection(IList<Animal> collection)
{
IList<AnimalDTO> result = new List<AnimalDTO>();
foreach (Animal animal in collection)
{
var _animal = ProduceAnimalDTOFromAnimal(animal);
if (_animal != null)
result.Add(_animal);
}
return result;
}
public AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal)
{
return this.factory.CreateAnimalDTO(animal);
}
}
更新 1
根据 sjb-sjb 和 ChiefTwoPencils 在评论中的建议,我从各自的工厂中删除了 switch 语句。结果如下所示:
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, @"(DTO)$", ""));
IList<PropertyInfo> props = new List<PropertyInfo>(srcType.GetProperties());
var propVals = props.Select(prop => prop.GetValue(DTO, null)).ToArray();
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
Type srcType = animal.GetType();
Type dtoType = Type.GetType($"{srcType.FullName}DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties())
{
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null)
{
dtoProperty.SetValue(dto, srcProperty.GetValue(animal));
}
}
return dto;
}
}
我在最初的问题中忘记提到的一件事是模型的构造函数可能具有比 DTO 对象具有的属性更多的参数。那和参数的顺序可能不一样。我认为在伪代码中,解决方案看起来像这样:
void AssignParamsToConstructor()
{
// Extract constructer parameters with names into an ordered list
// Match DTO properties with extracted parameters via name and type
// Fill any missing parameters with a default value or null
// Pass the final list of parameters as an array to Activator.CreateInstance method
}
我会暂时研究解决这个问题的方法,但欢迎任何指点。
更新 2
好的,所以我找到了一种解决先前问题的 hacky 解决方案,该问题是关于调用带有缺失或乱序参数的模型构造函数。
我创建了一个助手 class,它根据模型构造函数参数和 DTO 属性的组合创建一个有序参数数组。然后可以将该数组传递给 Activator.CreateInstance 而不会引起任何问题。
这是更新后的 AnimalFactory.CreateAnimal 方法:
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, @"(DTO)$", ""));
object[] propVals = Helpers.GenerateConstructorArgumentValueArray(modelType, DTO);
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
这是帮手 class:
public static class Helpers
{
public static object[] GenerateConstructorArgumentValueArray(Type type, object obj)
{
IList<(string, Type)> ctorArgTypes = new List<(string, Type)>();
IList<(string, object)> propVals = new List<(string, object)>();
// Get constructor arguments
ctorArgTypes = GetConstructorArgumentsAndTypes(type);
// Get object properties
propVals = GetObjectPropertiesAndValues(obj);
// Create args array
IList<object> paramVals = new List<object>();
foreach (var ctorArg in ctorArgTypes)
{
object val;
string _name = ctorArg.Item1.ToLower();
(string, object) _namedProp = propVals.Where(prop => prop.Item1.ToLower() == _name).FirstOrDefault();
if (_namedProp.Item2 != null)
{
val = _namedProp.Item2;
}
else
{
val = ctorArg.Item2.IsValueType ? Activator.CreateInstance(ctorArg.Item2) : null;
}
paramVals.Add(val);
}
return paramVals.ToArray();
}
private static IList<(string, Type)> GetConstructorArgumentsAndTypes(Type type)
{
List<(string, Type)> ctorArgs = new List<(string, Type)>();
TypeInfo typeInfo = type.GetTypeInfo();
ConstructorInfo[] ctors = typeInfo.DeclaredConstructors.ToArray();
ParameterInfo[] ctorParams = ctors[0].GetParameters();
foreach (ParameterInfo info in ctorParams)
{
ctorArgs.Add((info.Name, info.ParameterType));
}
return ctorArgs;
}
private static IList<(string, object)> GetObjectPropertiesAndValues(object obj)
{
List<(string, object)> props = new List<(string, object)>();
PropertyInfo[] propInfo = obj.GetType().GetProperties();
foreach (PropertyInfo info in propInfo)
{
string name = info.Name;
object val = info.GetValue(obj);
props.Add((name, val));
}
return props;
}
}
稍后我将不得不查看它以了解如何对其进行改进。然而,就目前而言,它完成了它的工作。
如果您有任何意见或意见,我将不胜感激。我会继续更新这个 post 直到我找到一个绝对的解决方案。
使用反射可以避免switch语句:
public AnimalDTO ToDTO( Animal src)
{
Type srcType = src.GetType();
Type dtoType = Type.GetType(srcType.Name + "DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties()) {
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null) {
dtoProperty.SetValue(dto, srcProperty.GetValue(src));
}
}
return dto;
}
要获得FromDTO方法,只需将ToDTO中的src和dto角色互换即可。
我不会在这种常见情况下重新发明轮子。
https://www.nuget.org/packages/automapper/
或
https://github.com/MapsterMapper/Mapster
https://www.nuget.org/packages/Mapster/
.......
了解如何使用其中一种框架。
下面是 mapster......“性能”数字......我就是这样找到它的(有人告诉我要注意自动映射器的性能)
所以我想出了一个似乎实现了我最初目标的解决方案。
之所以一开始很难解决,是因为原工厂class责任太多。它必须映射属性并创建一个新对象。将它们分开可以很容易地实现这个 post:
建议的通用工厂
我创建了一个简单的映射器,可以自动映射实体和 DTO 属性。更简单的解决方案是使用像 grandaCoder 建议的 AutoMapper。我的情况需要,否则自定义映射器是可行的方法。我还尝试尽量减少对 System.Reflection 的调用,这样性能就不会受到太大影响。
最终结果是一个工厂,它可以在任何实体和 DTO 对象之间进行转换,在它们之间映射属性,并且可以在没有默认/空构造函数的情况下实例化实体class。
我最终对原始 post 做了很多更改,所以我将最终结果上传到 github:https://github.com/MoMods/EntityDTOFactory
我对最终解决方案的任何其他想法/批评持开放态度。这是我第一次解决这类问题,所以很可能有更好的想法。
再次感谢您的帮助和建议!
我正在尝试将共享一个公共父对象的模型对象集合转换为一个 DTO。同样,我想反转该过程 - 将具有共同父对象的一组 DTO 放入一个模型对象中。
根据我的阅读,工厂模式似乎正是我正在寻找的。我还有一个 Producer class,它通过调用相关的工厂方法来处理对象模型和 DTO 之间的转换。
有一些限制:
- 这是一个开源库,我不想向现有的 class 添加方法。否则访问者模式就会起作用。如有错误请指正
- 同样,我不想向这个项目添加任何额外的包。据我了解,AutoMapper 可能是解决此问题的方法之一。
- 我是 C# 和设计模式的新手,所以如果我做的事情没有意义,我深表歉意。
这里是一些示例代码,代表了我到目前为止所做的尝试。我使用了网上的一些参考来获得一个想法,但它似乎有些不对。这里提到了另一种方式:Is a switch statement applicable in a factory method? c#,但我不确定这是否适用于这种情况。
欢迎任何批评或建议。
用法示例
Animal pet1 = new Pigeon("Pidgey", 100, false);
Animal pet2 = new Rattlesnake("Ekans", 20.0, true);
IList<Animal> myPets = new List<Animal>() { pet1, pet2 };
AnimalDTOProducer dtoProducer = new AnimalDTOProducer(new AnimalDTOFactory());
IList<AnimalDTO> myDTOs = new List<AnimalDTO>();
myDTOs = dtoProducer.ConvertAnimalCollection(myPets);
型号
public abstract class Animal
{
public Animal(string name)
{
Name = name;
}
public string Name { get; set; }
// business logic
}
public abstract class Bird : Animal
{
public Bird(string name, int maxAltitude, bool isReal)
: base(name)
{
Name = name;
MaxAltitude = maxAltitude;
IsReal = isReal;
}
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
// business logic
}
public class Pigeon : Bird
{
public Pigeon(string name, int maxAltitude, bool isReal)
: base(name, maxAltitude, isReal)
{
}
// business logic
}
public abstract class Snake : Animal
{
public Snake(string name, double length, bool isPoisonous)
: base(name)
{
Name = name;
Length = length;
IsPoisonous = isPoisonous;
}
public double Length { get; set; }
public bool IsPoisonous { get; set; }
// business logic
}
public class Rattlesnake : Snake
{
public Rattlesnake(string name, double length, bool isPoisonous)
: base(name, length, isPoisonous)
{
}
// business logic
}
DTOs
public abstract class AnimalDTO { }
public class PigeonDTO : AnimalDTO
{
public string Name { get; set; }
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
}
public class RattlesnakeDTO : AnimalDTO
{
public string Name { get; set; }
public double Length { get; set; }
public bool IsPoisonous { get; set; }
}
工厂
public interface IFactory { }
public interface IAnimalFactory : IFactory
{
Animal CreateAnimal(AnimalDTO DTO);
}
public interface IAnimalDTOFactory : IFactory
{
AnimalDTO CreateAnimalDTO(Animal animal);
}
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
switch (DTO)
{
case PigeonDTO _:
var pigeonDTO = (PigeonDTO)DTO;
return new Pigeon(pigeonDTO.Name, pigeonDTO.MaxAltitude, pigeonDTO.IsReal);
case RattlesnakeDTO _:
var rattlesnakeDTO = (RattlesnakeDTO)DTO;
return new Rattlesnake(rattlesnakeDTO.Name, rattlesnakeDTO.Length, rattlesnakeDTO.IsPoisonous);
// And many more ...
default:
return null;
}
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
switch (animal)
{
case Pigeon _:
var _pigeon = (Pigeon)animal;
return new PigeonDTO()
{
Name = _pigeon.Name,
MaxAltitude = _pigeon.MaxAltitude,
IsReal = _pigeon.IsReal
};
case Rattlesnake _:
var _rattlesnake = (Rattlesnake)animal;
return new RattlesnakeDTO()
{
Name = _rattlesnake.Name,
Length = _rattlesnake.Length,
IsPoisonous = _rattlesnake.IsPoisonous
};
// And many more ...
default:
return null;
}
}
}
生产者
public interface IProducer { }
public interface IAnimalProducer : IProducer
{
Animal ProduceAnimalFromDTO(AnimalDTO DTO);
}
public interface IAnimalDTOProducer : IProducer
{
AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal);
}
public class AnimalProducer : IAnimalProducer
{
private IAnimalFactory factory;
public AnimalProducer(IAnimalFactory factory)
{
this.factory = factory;
}
public IList<Animal> ConvertAnimalDTOCollection(IList<AnimalDTO> DTOCollection)
{
IList<Animal> result = new List<Animal>();
foreach (AnimalDTO DTO in DTOCollection)
{
var dto = ProduceAnimalFromDTO(DTO);
if (dto != null)
result.Add(dto);
}
return result;
}
public Animal ProduceAnimalFromDTO(AnimalDTO animalDTO)
{
return this.factory.CreateAnimal(animalDTO);
}
}
public class AnimalDTOProducer : IAnimalDTOProducer
{
private IAnimalDTOFactory factory;
public AnimalDTOProducer(IAnimalDTOFactory factory)
{
this.factory = factory;
}
public IList<AnimalDTO> ConvertAnimalCollection(IList<Animal> collection)
{
IList<AnimalDTO> result = new List<AnimalDTO>();
foreach (Animal animal in collection)
{
var _animal = ProduceAnimalDTOFromAnimal(animal);
if (_animal != null)
result.Add(_animal);
}
return result;
}
public AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal)
{
return this.factory.CreateAnimalDTO(animal);
}
}
更新 1
根据 sjb-sjb 和 ChiefTwoPencils 在评论中的建议,我从各自的工厂中删除了 switch 语句。结果如下所示:
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, @"(DTO)$", ""));
IList<PropertyInfo> props = new List<PropertyInfo>(srcType.GetProperties());
var propVals = props.Select(prop => prop.GetValue(DTO, null)).ToArray();
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
Type srcType = animal.GetType();
Type dtoType = Type.GetType($"{srcType.FullName}DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties())
{
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null)
{
dtoProperty.SetValue(dto, srcProperty.GetValue(animal));
}
}
return dto;
}
}
我在最初的问题中忘记提到的一件事是模型的构造函数可能具有比 DTO 对象具有的属性更多的参数。那和参数的顺序可能不一样。我认为在伪代码中,解决方案看起来像这样:
void AssignParamsToConstructor()
{
// Extract constructer parameters with names into an ordered list
// Match DTO properties with extracted parameters via name and type
// Fill any missing parameters with a default value or null
// Pass the final list of parameters as an array to Activator.CreateInstance method
}
我会暂时研究解决这个问题的方法,但欢迎任何指点。
更新 2
好的,所以我找到了一种解决先前问题的 hacky 解决方案,该问题是关于调用带有缺失或乱序参数的模型构造函数。
我创建了一个助手 class,它根据模型构造函数参数和 DTO 属性的组合创建一个有序参数数组。然后可以将该数组传递给 Activator.CreateInstance 而不会引起任何问题。
这是更新后的 AnimalFactory.CreateAnimal 方法:
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, @"(DTO)$", ""));
object[] propVals = Helpers.GenerateConstructorArgumentValueArray(modelType, DTO);
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
这是帮手 class:
public static class Helpers
{
public static object[] GenerateConstructorArgumentValueArray(Type type, object obj)
{
IList<(string, Type)> ctorArgTypes = new List<(string, Type)>();
IList<(string, object)> propVals = new List<(string, object)>();
// Get constructor arguments
ctorArgTypes = GetConstructorArgumentsAndTypes(type);
// Get object properties
propVals = GetObjectPropertiesAndValues(obj);
// Create args array
IList<object> paramVals = new List<object>();
foreach (var ctorArg in ctorArgTypes)
{
object val;
string _name = ctorArg.Item1.ToLower();
(string, object) _namedProp = propVals.Where(prop => prop.Item1.ToLower() == _name).FirstOrDefault();
if (_namedProp.Item2 != null)
{
val = _namedProp.Item2;
}
else
{
val = ctorArg.Item2.IsValueType ? Activator.CreateInstance(ctorArg.Item2) : null;
}
paramVals.Add(val);
}
return paramVals.ToArray();
}
private static IList<(string, Type)> GetConstructorArgumentsAndTypes(Type type)
{
List<(string, Type)> ctorArgs = new List<(string, Type)>();
TypeInfo typeInfo = type.GetTypeInfo();
ConstructorInfo[] ctors = typeInfo.DeclaredConstructors.ToArray();
ParameterInfo[] ctorParams = ctors[0].GetParameters();
foreach (ParameterInfo info in ctorParams)
{
ctorArgs.Add((info.Name, info.ParameterType));
}
return ctorArgs;
}
private static IList<(string, object)> GetObjectPropertiesAndValues(object obj)
{
List<(string, object)> props = new List<(string, object)>();
PropertyInfo[] propInfo = obj.GetType().GetProperties();
foreach (PropertyInfo info in propInfo)
{
string name = info.Name;
object val = info.GetValue(obj);
props.Add((name, val));
}
return props;
}
}
稍后我将不得不查看它以了解如何对其进行改进。然而,就目前而言,它完成了它的工作。
如果您有任何意见或意见,我将不胜感激。我会继续更新这个 post 直到我找到一个绝对的解决方案。
使用反射可以避免switch语句:
public AnimalDTO ToDTO( Animal src)
{
Type srcType = src.GetType();
Type dtoType = Type.GetType(srcType.Name + "DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties()) {
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null) {
dtoProperty.SetValue(dto, srcProperty.GetValue(src));
}
}
return dto;
}
要获得FromDTO方法,只需将ToDTO中的src和dto角色互换即可。
我不会在这种常见情况下重新发明轮子。
https://www.nuget.org/packages/automapper/
或
https://github.com/MapsterMapper/Mapster
https://www.nuget.org/packages/Mapster/
.......
了解如何使用其中一种框架。
下面是 mapster......“性能”数字......我就是这样找到它的(有人告诉我要注意自动映射器的性能)
所以我想出了一个似乎实现了我最初目标的解决方案。
之所以一开始很难解决,是因为原工厂class责任太多。它必须映射属性并创建一个新对象。将它们分开可以很容易地实现这个 post:
建议的通用工厂我创建了一个简单的映射器,可以自动映射实体和 DTO 属性。更简单的解决方案是使用像 grandaCoder 建议的 AutoMapper。我的情况需要,否则自定义映射器是可行的方法。我还尝试尽量减少对 System.Reflection 的调用,这样性能就不会受到太大影响。
最终结果是一个工厂,它可以在任何实体和 DTO 对象之间进行转换,在它们之间映射属性,并且可以在没有默认/空构造函数的情况下实例化实体class。
我最终对原始 post 做了很多更改,所以我将最终结果上传到 github:https://github.com/MoMods/EntityDTOFactory
我对最终解决方案的任何其他想法/批评持开放态度。这是我第一次解决这类问题,所以很可能有更好的想法。
再次感谢您的帮助和建议!