gpt4 book ai didi

c# - 有没有办法将键/值对列表转换为数据传输对象

转载 作者:行者123 更新时间:2023-11-30 12:36:48 24 4
gpt4 key购买 nike

...除了明显的列表循环和肮脏的 great case 语句外!

我已经在脑海中思考了几个 Linq 查询,但似乎没有任何结果。

如果有帮助的话,下面是一个 DTO 示例:

    class ClientCompany
{
public string Title { get; private set; }
public string Forenames { get; private set; }
public string Surname { get; private set; }
public string EmailAddress { get; private set; }
public string TelephoneNumber { get; private set; }
public string AlternativeTelephoneNumber { get; private set; }
public string Address1 { get; private set; }
public string Address2 { get; private set; }
public string TownOrDistrict { get; private set; }
public string CountyOrState { get; private set; }
public string PostCode { get; private set; }
}

恐怕我们无法控制以 KV 对形式获取数据这一事实。

虽然每个 KV 对到每个属性都有一个有效的映射,但我确实事先知道 key ,但它们的名称与 DTO 不同。

最佳答案

这是一个用于从字典加载 DTO 的优雅、可扩展、可维护且速度极快的解决方案。

创建一个控制台应用程序并添加这两个文件。其余的是 self 记录。

要点:

  • 简单、简短且可维护的映射类。
  • 使用动态方法进行高效的对象再水化。

注意:如果您复制了之前的 DynamicProperties.cs,您将需要获取此文件。我添加了一个标志以允许生成以前版本中没有的私有(private) setter 。

干杯。

program.cs

using System.Collections.Generic;
using System.Diagnostics;
using Salient.Reflection;

namespace KVDTO
{
/// <summary>
/// This is our DTO
/// </summary>
public class ClientCompany
{
public string Address1 { get; private set; }
public string Address2 { get; private set; }
public string AlternativeTelephoneNumber { get; private set; }
public string CountyOrState { get; private set; }
public string EmailAddress { get; private set; }
public string Forenames { get; private set; }
public string PostCode { get; private set; }
public string Surname { get; private set; }
public string TelephoneNumber { get; private set; }
public string Title { get; private set; }
public string TownOrDistrict { get; private set; }
}


/// <summary>
/// This is our DTO Map
/// </summary>
public sealed class ClientCompanyMapping : KeyValueDtoMap<ClientCompany>
{
static ClientCompanyMapping()
{
AddMapping("Title", "Greeting");
AddMapping("Forenames", "First");
AddMapping("Surname", "Last");
AddMapping("EmailAddress", "eMail");
AddMapping("TelephoneNumber", "Phone");
AddMapping("AlternativeTelephoneNumber", "Phone2");
AddMapping("Address1", "Address1");
AddMapping("Address2", "Address2");
AddMapping("TownOrDistrict", "City");
AddMapping("CountyOrState", "State");
AddMapping("PostCode", "Zip");
}
}


internal class Program
{
private const string Address1 = "1243 Easy Street";
private const string CountyOrState = "Az";
private const string EmailAddress = "nunya@bidnis.com";
private const string Forenames = "Sky";
private const string PostCode = "85282";
private const string Surname = "Sanders";
private const string TelephoneNumber = "800-555-1212";
private const string Title = "Mr.";
private const string TownOrDistrict = "Tempe";

private static void Main(string[] args)
{
// this represents our input data, some discrepancies
// introduced to demonstrate functionality of the map

// the keys differ from the dto property names
// there are missing properties
// there are unrecognized properties
var input = new Dictionary<string, string>
{
{"Greeting", Title},
{"First", Forenames},
{"Last", Surname},
{"eMail", EmailAddress},
{"Phone", TelephoneNumber},
// missing from this input {"Phone2", ""},
{"Address1", Address1},
// missing from this input {"Address2", ""},
{"City", TownOrDistrict},
{"State", CountyOrState},
{"Zip", PostCode},
{"SomeOtherFieldWeDontCareAbout", "qwerty"}
};


// rehydration is simple and FAST

// instantiate a map. You could store instances in a dictionary
// but it is not really necessary for performance as all of the
// work is done in the static constructors, so no matter how many
// times you 'new' a map, it is only ever built once.

var map = new ClientCompanyMapping();

// do the work.
ClientCompany myDto = map.Load(input);





// test
Debug.Assert(myDto.Address1 == Address1, "Address1");
Debug.Assert(myDto.Address2 == null, "Address2");
Debug.Assert(myDto.AlternativeTelephoneNumber == null, "AlternativeTelephoneNumber");
Debug.Assert(myDto.CountyOrState == CountyOrState, "CountyOrState");
Debug.Assert(myDto.EmailAddress == EmailAddress, "EmailAddress");
Debug.Assert(myDto.Forenames == Forenames, "Forenames");
Debug.Assert(myDto.PostCode == PostCode, "PostCode");
Debug.Assert(myDto.Surname == Surname, "Surname");
Debug.Assert(myDto.TelephoneNumber == TelephoneNumber, "TelephoneNumber");
Debug.Assert(myDto.Title == Title, "Title");
Debug.Assert(myDto.TownOrDistrict == TownOrDistrict, "TownOrDistrict");
}
}

/// <summary>
/// Base mapper class.
/// </summary>
/// <typeparam name="T"></typeparam>
public class KeyValueDtoMap<T> where T : class, new()
{
private static readonly List<DynamicProperties.Property> Props;
private static readonly Dictionary<string, string> KvMap;

static KeyValueDtoMap()
{
// this property collection is built only once
Props = new List<DynamicProperties.Property>(DynamicProperties.CreatePropertyMethods(typeof(T)));
KvMap=new Dictionary<string, string>();
}

/// <summary>
/// Adds a mapping between a DTO property and a KeyValue pair
/// </summary>
/// <param name="dtoPropertyName">The name of the DTO property</param>
/// <param name="inputKey">The expected input key</param>
protected static void AddMapping(string dtoPropertyName,string inputKey)
{
KvMap.Add(dtoPropertyName,inputKey);
}

/// <summary>
/// Creates and loads a DTO from a Dictionary
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public T Load(Dictionary<string, string> input)
{
var result = new T();
Props.ForEach(p =>
{
string inputKey = KvMap[p.Info.Name];
if (input.ContainsKey(inputKey))
{
p.Setter.Invoke(result, input[inputKey]);
}
});
return result;
}
}
}

DynamicProperties.cs

/*!
* Project: Salient.Reflection
* File : DynamicProperties.cs
* http://spikes.codeplex.com
*
* Copyright 2010, Sky Sanders
* Dual licensed under the MIT or GPL Version 2 licenses.
* See LICENSE.TXT
* Date: Sat Mar 28 2010
*/

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

namespace Salient.Reflection
{
/// <summary>
/// Gets IL setters and getters for a property.
/// </summary>
public static class DynamicProperties
{
#region Delegates

public delegate object GenericGetter(object target);

public delegate void GenericSetter(object target, object value);

#endregion

public static IList<Property> CreatePropertyMethods(Type T)
{
var returnValue = new List<Property>();

foreach (PropertyInfo prop in T.GetProperties())
{
returnValue.Add(new Property(prop));
}
return returnValue;
}


public static IList<Property> CreatePropertyMethods<T>()
{
var returnValue = new List<Property>();

foreach (PropertyInfo prop in typeof (T).GetProperties())
{
returnValue.Add(new Property(prop));
}
return returnValue;
}


/// <summary>
/// Creates a dynamic setter for the property
/// </summary>
/// <param name="propertyInfo"></param>
/// <returns></returns>
/// <source>
/// http://jachman.wordpress.com/2006/08/22/2000-faster-using-dynamic-method-calls/
/// </source>
public static GenericSetter CreateSetMethod(PropertyInfo propertyInfo)
{
/*
* If there's no setter return null
*/
MethodInfo setMethod = propertyInfo.GetSetMethod(true);
if (setMethod == null)
return null;

/*
* Create the dynamic method
*/
var arguments = new Type[2];
arguments[0] = arguments[1] = typeof (object);

var setter = new DynamicMethod(
String.Concat("_Set", propertyInfo.Name, "_"),
typeof (void), arguments, propertyInfo.DeclaringType);
ILGenerator generator = setter.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
generator.Emit(OpCodes.Ldarg_1);

if (propertyInfo.PropertyType.IsClass)
generator.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
else
generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);

generator.EmitCall(OpCodes.Callvirt, setMethod, null);
generator.Emit(OpCodes.Ret);

/*
* Create the delegate and return it
*/
return (GenericSetter) setter.CreateDelegate(typeof (GenericSetter));
}


/// <summary>
/// Creates a dynamic getter for the property
/// </summary>
/// <param name="propertyInfo"></param>
/// <returns></returns>
/// <source>
/// http://jachman.wordpress.com/2006/08/22/2000-faster-using-dynamic-method-calls/
/// </source>
public static GenericGetter CreateGetMethod(PropertyInfo propertyInfo)
{
/*
* If there's no getter return null
*/
MethodInfo getMethod = propertyInfo.GetGetMethod(true);
if (getMethod == null)
return null;

/*
* Create the dynamic method
*/
var arguments = new Type[1];
arguments[0] = typeof (object);

var getter = new DynamicMethod(
String.Concat("_Get", propertyInfo.Name, "_"),
typeof (object), arguments, propertyInfo.DeclaringType);
ILGenerator generator = getter.GetILGenerator();
generator.DeclareLocal(typeof (object));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
generator.EmitCall(OpCodes.Callvirt, getMethod, null);

if (!propertyInfo.PropertyType.IsClass)
generator.Emit(OpCodes.Box, propertyInfo.PropertyType);

generator.Emit(OpCodes.Ret);

/*
* Create the delegate and return it
*/
return (GenericGetter) getter.CreateDelegate(typeof (GenericGetter));
}

#region Nested type: Property

public class Property
{
public GenericGetter Getter;
public PropertyInfo Info;
public GenericSetter Setter;

public Property(PropertyInfo info)
{
Info = info;
Setter = CreateSetMethod(info);
Getter = CreateGetMethod(info);
}
}

#endregion
}
}

关于c# - 有没有办法将键/值对列表转换为数据传输对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2543774/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com