简体   繁体   English

C#类到类的转换

[英]C# class to class conversion

Let's say I have multiple pairs of two different classes that have the exact same properties. 假设我有两个不同的类,它们对具有完全相同的属性。

public class Class1
{
    public int IntValue { get; set; }
    public string StringValue { get; set; }
}

public class Class2
{
    public int IntValue { get; set; }
    public string StringValue { get; set; }
}

Is it possible to create a method that takes any object as an argument and returns an object where I pass in Class1 and it returns Class2 or vise versa without knowing what class will be passed in? 是否有可能创建一个将任何object作为参数并返回我在Class1传递的object并返回Class2或相反的object的方法,反之亦然,而又不知道将传递什么类? We can assume that the two classes will share the exact same properties. 我们可以假设这两个类将共享完全相同的属性。 We would need to define the Type that we want returned when we call the method. 我们需要定义调用该方法时要返回的Type

The only way without knowing the type at compile time would be to use reflection to: 在编译时不知道类型的唯一方法是使用反射来:

  • get a list of all properties of each type 获取每种类型的所有属性的列表
  • find the matching properties by name 通过名称查找匹配的属性
  • for each property: 对于每个属性:
    • get the value from object 1 从对象1获取值
    • set the value on object 2 (converting if necessary) 设置对象2的值(必要时进行转换)

Tools like AutoMapper do a decent job out-of-the-box, but almost always need some sort of custom configuration when mapping from one type to another. 诸如AutoMapper之类的工具开箱即可完成不错的工作,但是从一种类型映射到另一种类型时, 几乎总是需要某种自定义配置。

If you have two types that have the exact same properties and types, then perhaps you need a base type for the common properties? 如果您有两个具有完全相同的属性和类型的类型,那么也许您需要通用属性的基本类型?

Assuming you can modify your code to have all the classes implement a common interface: 假设您可以修改代码以使所有类都实现一个公共接口:

public interface SomeInterface
{
    int IntValue { get; set; }
    string StringValue { get; set; }
}

public class Class1 : SomeInterface
{
    public int IntValue { get; set; }
    public string StringValue { get; set; }
}

public class Class2 : SomeInterface etc

Then a simple method can be created to convert from one to the other: 然后可以创建一个简单的方法从一个转换为另一个:

public T1 Convert<T1, T2>(T2 source) where T1 : SomeInterface, T2 : SomeInterface
{
    return new T1
    {
        IntValue = source.IntValue,
        StringValue = source.StringValue
    };
}

Then you use it in the following way: 然后,您可以通过以下方式使用它:

var x = new Class1 { IntValue = 1, StringValue = "someText" };
...
Class2 y = Convert(x);

However a more practical solution would be to remove the multiple classes, all with the same structure, and replace them with a common one. 但是,更实际的解决方案是删除所有具有相同结构的多个类,并用一个通用的类替换它们。

Yes, it is possible using reflection and iterating through each property. 是的,可以使用反射并遍历每个属性。 The only problem is when your class hides parameterless constructor, but then instead of creating this object inside the converter, you can pass it through parameter. 唯一的问题是,当您的类隐藏无参数构造函数时,您可以通过参数传递它,而不是在转换器内部创建此对象。

The solution below doesn't require both classes to contain the same properties. 下面的解决方案不需要两个类都包含相同的属性。

using System;
using System.Linq;

namespace Utils
{
    public static class TypeConverter
    {
        public static TDestination Convert<TSource, TDestination>(TSource source)
        {
            var destination = Activator.CreateInstance<TDestination>();
            var destProperties = destination.GetType()
                                            .GetProperties()
                                            .ToDictionary(x => x.Name);

            foreach (var prop in source.GetType().GetProperties())
            {
                if (destProperties.ContainsKey(prop.Name))
                {
                    destProperties[prop.Name].SetValue(destination, prop.GetValue(source));
                }
            }

            return destination;
        }
    }
}

Usage: 用法:

var c1 = new Class1() { IntValue = 1, StringValue = "aaaa" };
var c2 = TypeConverter.Convert<Class1, Class2>(c1);

You only need to use System.Reflection and the use of Dictionaries for mapping data if you do something like. 如果执行类似的操作,则只需要使用System.Reflection和使用Dictionary来映射数据。

public T ConvertClass<T>(X objectModel) 
{
    Dictionary<string,string> columnMapping = new Dictionary<string,string>
    string valueTempplete = "'{value}'"
    foreach(var prop in objectModel.GetType().GetProperties(BindingFlags)) 
    {
        var propertyName = prop.Name;
        var value = objectModel.GetType().GetProperty(propertName).GetValue(objectModel, null).ToString();
        columnMapping.Add(propertyName, valueTemplete.Replace("{value}",value))
    }
}

The reason behind using the value template is so you don't create a new instance of the string every time you go into the loop. 使用值模板的原因是,您不必每次进入循环时都创建字符串的新实例。 You will have to figure out a way to map the dictionary data to your T object. 您将必须找出一种将字典数据映射到T对象的方法。 After you figure that out you can just pass in the class you want to convert to into the <>, and the object you are converting from into the parameter. 弄清楚之后,您可以将要转换的类传递给<>,并将要从其转换的对象传递给参数。 I know this is not a complete answer but should give you a good start. 我知道这不是一个完整的答案,但应该为您提供一个良好的开端。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM