Cruces
Cruces

Reputation: 3119

How to convert class with generic type to class with object as generic type in C#

Hello I'm using Visual Studio 2005 (because I need compact framework support) and my problem is with generics.

I have created an abstract class called AbstractDAO which is my base

From that I am creating other classes like DocumentDAO,HeaderDAO etc which represent different tables on my database

What I wish to do is retrieve a certain number of the above mentioned DAO classes, but as an AbstractDAO (the abstract class has a number of concrete implementations that I wish to use)

What I tried is

AbstractDAO<object> dao = new DocumentDAO();
AbstractDAO<object> dao = (AbstractDAO<object>)new DocumentDAO();
AbstractDAO<T> dao = new DocumentDAO();

I need the above because I have created a function that transfers data from one table to another similar table in a different database, so it would (if it worked) go something like this

AbstractDAO<object> dao_local = new DocumentDAO(local_database);
AbstractDAO<object> dao_remote = new DocumentDAO(remote_database);      
do_transfer(dao_local,dao_remote)

void do_transfer(AbstractDAO<object> from, AbstractDAO<object> to) {
     List<object> items = from.get_all();
     to.insert(items);
}

Is there any way to do the above?

Upvotes: 1

Views: 1568

Answers (4)

Cruces
Cruces

Reputation: 3119

So I finally found the answer to what I was trying to do, instead of assigning abstractDAO to something I created a factory that would retrieve the required AbstractDAO according to what type the generic was, and used this function

private bool transfer<T>(){
    AbstractDAO<T> local = DAOFactory.get<T>(local_database);
    AbstractDAO<T> remote = DAOFactory.get<T>(remote_database);
    List<T> items = local.get_all();
    foreach (T item in items) {
        remote.insert(item);
    } 
}

That way I can call this function like this: transfer< Document >(); transfer< Header >();

etc. and do a full transfer

edit: just for completeness' shake this is the factory I created

    public static AbstractDAO<T> get<T>(Database database) {
        Type t = typeof(T);
        if (t == typeof(Document)) {
            return new DocumentDAO(database) as AbstractDAO<T>;
        } else if (t == typeof(Header)) {
            return new HeaderDAO(database) as AbstractDAO<T>;
        } etc.
    }

Upvotes: 0

Tedd Hansen
Tedd Hansen

Reputation: 12314

Any implementation of AbstractDAO<T> is compiled to a separate object type where T is replaced with the type. See "Is generics runtime or compile time polymorphism?" for more information on how this happens. In short, don't let the <T> fool you.

This means that you can't assign DocumentDAO to AbstractDAO<object> any more than you can assign String to it. Also a generic type is not the same as inheriting, which seems to be what you are trying to achieve.

In either case there are two standard solutions, as already mentioned.

The first is to operate on interfaces. You create an interface for the common properties and have AbstractDAO<T> or any other inherit from this. Then most of the time you simply operate on interfaces. Exactly how you organize it is up to you.

The second is to perform a shallow copy of the object. This means copying values and references from one object to the other. For this you usually use an object mapper like AutoMapper. This tutorial should get you started..

Upvotes: 1

Kovalenko Ivan
Kovalenko Ivan

Reputation: 172

You can try to use Automapper to transfer your objects like this:

void do_transfer(AbstractDAO<FirstType> from, AbstractDAO<SecondType> to) 
{
    Mapper.Initialize(cfg=>cfg.CreateMap<FirstType, SecondType>);

    List<FirstType> fromItems = from.get_all();
    List<SecondType> itemsToInsert = 
        Mapper.Map<List<FirstType>, List<SecondType>>(fromItems);
    to.insert(itemsToInsert);
}

By default automapper will map fields with same names. You can create configurations for complex type mapping.

Upvotes: 0

Jens
Jens

Reputation: 2617

That will only work if your class hierachy is like this:

class DocumentDAO : AbstractDAO<object> {
    //...
}

By your comment it seems like you have a type hierarchy like this:

class DocumentDAO : AbstractDAO<SomeType> {
    public override SomeType Foo() {
        //...
        return someValue;
    }
    //...
}
class AbstractDAO<T> {
    public abstract T Foo();
    //...
}

You probably want to refactor AbstractDAO to implement a non generic interface like IAbstractDAO:

class IAbstractDAO {
    object Foo();
    //...
}

class AbstractDAO<T> {
    public object Foo() {
        return Foo();
    }
    public abstract T Foo();
    //...
}

Upvotes: 1

Related Questions