简体   繁体   中英

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? 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.

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
    • set the value on object 2 (converting if necessary)

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.

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.

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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