This commit is contained in:
Александр Бабаев 2022-02-23 19:58:03 +03:00
parent e08aeca7aa
commit bff4cb735c
2 changed files with 136 additions and 4 deletions

132
anbs_cp/SimpleMapper.cs Normal file
View File

@ -0,0 +1,132 @@
using System.Reflection;
namespace anbs_cp;
/// <summary>
/// Класс перевода одинаковых свойств из класса TF в класс T.
/// Оригинальные автор(-ы): keenthinker и Avtandil Kavrelishvili.
/// Улучшения: А. Н. Бабаев
/// URL: https://stackoverflow.com/questions/20410234/how-to-automatically-map-the-values-between-instances-of-two-different-classes-i
/// </summary>
public static class SimpleMapper
{
/// <summary>
/// Перевод одинаковых свойств из класса F в класс TT.
/// </summary>
/// <param name="from">Экземпляр класса F</param>
/// <param name="to">Ссылка на экземпляр класса T</param>
/// <param name="mode">Тип сопоставления</param>
/// <param name="list">Список параметров для сопоставления</param>
/// <typeparam name="TF">Класс-родитель</typeparam>
/// <typeparam name="T">Класс-приёмник</typeparam>
public static void MapEx<TF, T> (TF from, ref T to, MapMode mode, List<string> list)
{
//Копирую поля
Type typeOfA = typeof(TF);
Type typeOfB = typeof(T);
foreach (FieldInfo fieldOfA in typeOfA.GetFields())
{
//Проверяем выполнение условия и прерываем, если не выполняется
if (CheckCondition(fieldOfA.Name, fieldOfA.GetValue(from), mode, list))
continue;
//Получаем FieldInfo для b по имени поля a
FieldInfo? fieldOfB = typeOfB.GetField(fieldOfA.Name);
//Присваиваю поля типа B значение поля типа A
fieldOfB?.SetValue(to, fieldOfA.GetValue(from));
}
//Копирую свойства
foreach (PropertyInfo propertyOfA in typeOfA.GetProperties())
{
//Проверяем выполнение условия и прерываем, если не выполняется
if (CheckCondition(propertyOfA.Name, propertyOfA.GetValue(from), mode, list))
continue;
//Получаем PropertyInfo для b по имени свойства a
PropertyInfo? propertyOfB = typeOfB.GetProperty(propertyOfA.Name);
//Присваиваю свойству типа B значение свойства типа A
propertyOfB?.SetValue(to, propertyOfA.GetValue(from));
}
}
/// <summary>
/// Перевод одинаковых свойств из класса F в класс TT (режим "сопоставление всех параметров").
/// </summary>
/// <param name="from">Параметр класса F</param>
/// <typeparam name="TF">Класс-родитель</typeparam>
/// <typeparam name="T">Класс-приёмник</typeparam>
/// <returns>Элемент класса T</returns>
public static T Map<TF, T> (TF from)
{
//Создаю элемент
// ReSharper disable once NullableWarningSuppressionIsUsed
T result = (T)Activator.CreateInstance(typeof(T))!;
//Сопоставляю по принципу "сопоставление всех параметров"
MapEx(from, ref result, MapMode.MapFull, new());
//Вывожу в результат
return result;
}
/// <summary>
/// Проверка выполнения условия
/// </summary>
/// <param name="itemName">Имя элемента</param>
/// <param name="itemValue">Значение элемента</param>
/// <param name="mode">Режим проверки</param>
/// <param name="list">Список игнорирования/добавления</param>
/// <returns></returns>
private static bool CheckCondition (string itemName, object? itemValue, MapMode mode, ICollection<string> list)
{
//Если режим "Только список" и поля нет в списке,
//либо режим "Только не в списке" и поле есть в списке
//или режим "Только не пустые" и значение поля пустое,
//или режим "Только не по умолчанию" и значение по умолчанию
//то пропускаем
bool result =
mode switch {
MapMode.MapFull => true,
MapMode.MapNotNull => itemValue != null,
MapMode.MapByList => list.Contains(itemName),
MapMode.MapIgnoreList => !list.Contains(itemName),
MapMode.MapNotDefault => itemValue != default,
MapMode.MapNotNullOrDefault => itemValue != null || itemValue != default,
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null)
};
//Возвращаем результат
return result;
}
/// <summary>
/// Перечисление типов сопоставления
/// </summary>
public enum MapMode
{
/// <summary>
/// Сопоставление всех параметров
/// </summary>
MapFull = 0,
/// <summary>
/// Сопоставление не пустых параметров
/// </summary>
MapNotNull = 1,
/// <summary>
/// Сопоставление по списку
/// </summary>
MapByList = 2,
/// <summary>
/// Сопоставление исключая список
/// </summary>
MapIgnoreList = 3,
/// <summary>
/// Сопоставление параметров, которые не равны значению по умолчанию
/// </summary>
MapNotDefault = 4,
/// <summary>
/// Сопоставление не пустых параметров, которые не равны значению по умолчанию (NotNull и NotDefault одновременно)
/// </summary>
MapNotNullOrDefault = 5,
}
}

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>1.2021.1215</Version>
<Version>1.2022.223</Version>
<Authors>Alexander Babaev</Authors>
<Product>ANB Software Components Pack</Product>
<Description>Library of some useful functions in C# language.</Description>
@ -15,8 +15,8 @@
<SignAssembly>False</SignAssembly>
<PackageProjectUrl>https://github.com/GoodBoyAlex/anbsoftware_componentspack</PackageProjectUrl>
<RepositoryUrl>https://github.com/GoodBoyAlex/anbsoftware_componentspack</RepositoryUrl>
<AssemblyVersion>1.2021.1215</AssemblyVersion>
<FileVersion>1.2021.1215</FileVersion>
<AssemblyVersion>1.2022.0223</AssemblyVersion>
<FileVersion>1.2022.223</FileVersion>
<PackageId>ANBSoftware.ComponentsPack</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<AnalysisLevel>6.0</AnalysisLevel>
@ -33,7 +33,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop" Version="17.0.31902.203" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop" Version="17.1.32210.191" />
</ItemGroup>
</Project>