Boomit
Boomit

Reputation: 187

Method for casting generic objects c#

I have a couple of objects that have a corresponding object with identical properties.

class Source1
{
    int id;
    string name;
    DateTime date;
}

class Destination1
{
    int id;
    string name;
    DateTime date;
}

class Source2
{
    int id;
    string code;
    double price;
}

class Destination2
{
    int id;
    string code;
    double price;
}

Now I want to make a method with generic types that can cast an object into his corresponding object.

public TDestination Cast<TSource, TDestination>(TSource source)
{
    //TDestination destination = (TDestination) source;
    return destination;
}

Upvotes: 1

Views: 169

Answers (3)

Michael Hoffmann
Michael Hoffmann

Reputation: 2436

Boris Calens pointed out Automapper, which is great, but if you want to avoid using outside code, a home-made solution for your example problem is pretty simple:

using System.Reflection;

...

TDestination Copy<TSource, TDestination>(TSource source)
where TDestination : new()
{
    TDestination dest = new TDestination();

    foreach (FieldInfo srcField in typeof(TSource).GetFields())
    {
        foreach (FieldInfo destField in typeof(TDestination).GetFields())
        {
            if (destField.Name == srcField.Name && destField.FieldType == srcField.FieldType)
            {
                destField.SetValue(dest, srcField.GetValue(source));
            }
        }
    }

    return dest;
}

You could also easily loop through the properties of the respective types; specify binding flags to filter which fields/properties get copied; and expand the comparison for determining whether the two members are of the same type (i.e. checking whether one type is derived from another).

My answer to this question (which you may also find helpful) shows a similar example, comparing properties and fields.

Upvotes: 0

Magnus
Magnus

Reputation: 46997

Your best option here is to introduce a common interface (or base class). There is no other way to cast an item into another.

public interface IItem
{
    int id {get;set;}
    string name {get;set;}
    DateTime date {get;set;}
}

class Source1 : IItem
{
    public int id {get;set;}
    public  string name {get;set;}
    public  DateTime date {get;set;}
}

class Destination1 : IItem
{
    public int id {get;set;}
    public string name {get;set;}
    public DateTime date {get;set;}
}

You can then just cast the object into the interface and access the properties.

var item1 = (IItem)sourceItem;
var item2 = (IItem)destinationItem;

If you don't want to do that another option would be to using reflection go trough the properties in the source and create a new object of the destination type and try to map properties with shared names. This would however create a new object and is not the same at all as casting. There are libraries such as AutoMapper that can help you with this.

AutoMapper.Mapper.CreateMap<Source1, Destination1>();
var destItem = AutoMapper.Mapper.Map<Destination1 >(sourceItem);

Upvotes: 5

Boris Callens
Boris Callens

Reputation: 93407

As Magnus points out, if you want to actually cast, interfaces are your way to go. However, I'm thinking you might be actually looking at converting rather then casting.

I would consider checking Automapper as it exists for exactly that.
From the documentation:

var source = new Source<int> { Value = 10 };  
var dest = mapper.Map<Source<int>, Destination<int>>(source);  
dest.Value.ShouldEqual(10);

You can configure mappings between two types by either naming conventions (even custom naming conventions), custom mappers or a combination of both. The most common use case I have seen for this is mapping a datatransfer object to a model and back again.

If one object is basically the other object with some extra logic and properties the Decorator pattern might be what you are looking for. Here you basically wrap (decorate) one object with some extra stuff and the decorating object links everything through to the original object.

Upvotes: 1

Related Questions