C# 结构到类的通用转换器,反之亦然

C# 结构到类的通用转换器,反之亦然,c#,.net,wpf,C#,.net,Wpf,我想要两个这样的转换器: public class PacMan<T2> where T2 : new() { public static List<T1> ArrayToList<T1>(T2[] array) { var list = new List<T1>(array.Length); for (int i = 0; i < array.Length; i++) list.Add(arr

我想要两个这样的转换器:

public class PacMan<T2> where T2 : new()
{
    public static List<T1> ArrayToList<T1>(T2[] array)
    {
        var list = new List<T1>(array.Length);
        for (int i = 0; i < array.Length; i++) list.Add(array[i]);
        return list;
    }

    public static T2[] ListToArray<T1>(List<T1> list)
    {
        var array = new T2[list.Count];
        for (int i = 0; i < list.Count; i++) array[i] = list[i];
        return array;
    }
}
下面是结构:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PerSecStruct
{
    //23 bytes
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)]
    public string YQ;
    public float EPS;
    public float NAV;
    public float Cash;
    public float Debt;
}
编辑

在第二种方法中,我现在有:

public static T2[] ListToarray<T1>(List<T1> list)
{
    var structFields = typeof(PerSecStruct).GetFields(BindingFlags.Instance | BindingFlags.Public);
    var classFields = typeof(PerSec).GetProperties(BindingFlags.Instance | BindingFlags.Public);
    classFields = classFields.Where(x => structFields.Select(y => y.Name).Contains(x.Name)).ToArray();
    var fieldsDictionary = structFields.Zip(classFields, (k, v) => new { StructField = k, ClassField = v }).ToDictionary(x => x.StructField, x => x.ClassField);

    var array = new T2[list.Count];
    for (int i = 0; i < list.Count; i++)
    {
        var psStruct = array[i];
        var psClass = list[i];

        foreach (var entry in fieldsDictionary)
        {
            var value = entry.Value.GetValue(psClass);
            entry.Key.SetValue(psStruct, value);
        }
    }
    return array;
}
我不需要那些绑定的旗帜!要转换回列表,我必须使用其他方法:

public static List<T1> ArrayToList<T1>(T2[] array) where T1 : new()
{
    var fields = typeof(T2).GetFields();
    var properties = typeof(T1).GetProperties();

    var list = new List<T1>(array.Length);
    for (int i = 0; i < array.Length; i++)
    {
        var obj = new T1();
        foreach (var property in properties)
        {
            var value = fields.First(x => x.Name == property.Name).GetValue(array[i]);
            property.SetValue(obj, value);
        }
        list.Add(obj);
    }
    return list;
}

这可以使用反射来完成,尽管我也强烈建议您查看注释中指出的AutoMapper,但是如果您只需要这一个结构,您可以编写自己的实现

反射是进程检查、内省和修改自身结构和行为的能力,在C语言中,我们使用System.Reflection命名空间来实现这一点

因此,我们希望将一个结构的所有公共字段映射到另一个结构的所有公共属性,为此,我们首先需要获取结构上的所有公共字段和类上的所有属性,如下所示:

为此,我们需要每个

var-psStruct=。。。; var psClass=。。。; //BindingFlags.Instance表示所有实例字段都是非静态的 //BindingFlags.Public仅表示公共字段 var structFields=typeofPerSecStruct.GetFieldsBindingFlags.Instance | BindingFlags.Public; //BindingFlags是相同的,但我们使用“GetProperties”,因为您声明了属性而不是字段 var classFields=typeofPerSec.GetPropertiesBindingFlags.Instance | BindingFlags.Public; 现在我们有了结构上的字段和类上的属性的列表,这样我们就可以开始映射了:

//首先过滤类上的列表,以确保我们也只有结构的属性 classFields=classFields.Wherex=>structFields.Selecty=>y.Name.Containsx.Name; //ToDictionary将两个列表合并为一个列表 var fieldsDictionary=structFields.ZipclassFields,k,v=>new{StructField=k,ClassField=v}.todictionary=>x.StructField,x=>x.ClassField; 字段中的foreach var条目字典 { //从psStruct对象获取值 var值=entry.Key.GetValuepsStruct; //psClass对象上的设置值这可以是一行,但我更喜欢它,因为它更可读 entry.Value.SetValuepsClass,Value; } 如何使用此功能的具体示例:

公共静态列表作为可枚举源,其中TTarget:new; { var sourceFields=typeofTSource.GetFieldsBindingFlags.Instance | BindingFlags.Public; var targetProperties=TypeOfTarget.GetPropertiesBindingFlags.Instance | BindingFlags.Public; var-mapping=sourceFields.ZiptargetProperties,k,v=>new{Source=k,Target=v}.ToDictionaryx=>x.Source,x=>x.Target; var retval=新列表; 源中的foreach var sourceObject { var mappedObject=新的TTarget; 映射中的foreach var m { var value=entry.Key.GetValuesourceObject; entry.Value.SetValuemappedObject,值; } retval.AddmappedObject; } 返回返回; } 我在获取结构/类字段/属性时添加了OrderBy子句,因为否则结构/类中的顺序或声明必须是相同的,就像这样,这无关紧要


目前这并不是双向的,但是如果您决定用属性替换结构中的字段,您可以替换TypeOfSource.GetFields。。。使用typeofTSource.GetProperties…,它将以两种方式工作

您可以使用大多数序列化程序,例如:

使用Newtonsoft.Json; ... 内部静态类MyConverter { 内部静态转换对象源 { 字符串json=JsonConvert.SerializeObjectsource; T result=JsonConvert.DeserializeObjectjson; 返回结果; } } 用法:

var s1=新的PerSecStruct{YQ=1,每股收益=2,资产净值=3,现金=4,债务=5}; //反对 var o=MyConverter.Converts1; //返回结构 var s2=MyConverter.Converto;
当鼠标悬停在红色的曲线上时,会出现什么错误?还有,你的问题是什么?将数组转换为列表就像编写var list=newlistarray一样简单;反之亦然,它的var array=list.ToArray;我建议你去看看AutoMapper。非常方便的c库转换。这能回答你的问题吗@EmonHaque为什么不呢?使用JSON序列化程序相对于使用反射有什么好处?@MindSwipe for me-simplicity@EmonHaque您的GetFields和GetProperties调用中缺少BindingFlags参数,即使我在GetFields和GetProperties调用中使用这些标志,它也不起作用现在我读了更多的代码,您正在读取阵列中空插槽的类型。2个问题:1为什么不使用foreach?这将使阅读和理解代码更加容易。2为什么要尝试将类对象列表转换为结构对象数组?它仍然不起作用!我编辑了最后一个编辑部分,以显示我如何使用您的approach@EmonHaque有关映射的实现,请参见我的更新答案
public static T2[] ListToarray<T1>(List<T1> list)
{
    var fields = typeof(T2).GetFields();
    var properties = typeof(T1).GetProperties();
    var array = new T2[list.Count];

    for (int i = 0; i < list.Count; i++)
    {
        foreach (var field in fields)
        {
            var value = properties.First(x => x.Name == field.Name).GetValue(list[i]);
            field.SetValueDirect(__makeref(array[i]), value);
        }
    }
    return array;
}
public static List<T1> ArrayToList<T1>(T2[] array) where T1 : new()
{
    var fields = typeof(T2).GetFields();
    var properties = typeof(T1).GetProperties();

    var list = new List<T1>(array.Length);
    for (int i = 0; i < array.Length; i++)
    {
        var obj = new T1();
        foreach (var property in properties)
        {
            var value = fields.First(x => x.Name == property.Name).GetValue(array[i]);
            property.SetValue(obj, value);
        }
        list.Add(obj);
    }
    return list;
}