Question

I have been playing with loosely coupling my data access layer. I found the Dependency injection process quite helpful, but ran into a bit of a conundrum when considering the use of generics.

Is there a way to get a class that supports a generic type parameter to truly be both decoupled and type safe? My concern is that even if you write to a common interface if the derived type down the road is different than the entities you originally coded to then you can run into some nasty runtime errors that the compiler may not catch.

The issue is that when I write the code to get the data from the database and hydrate my object I am faced with a conundrum when trying to implement it on the next layer up. If I pass in an class such as Foo2 below I can break my code as there is no "implicit" conversion. I had been working with reflection to try and loosen things up, but I keep coming back to the issue that when getting the data from the database I need to hydrate a concrete type. That type then creates issues with casting and type assurance. Additionally, if I wanted to abstract all the methods for all the many types in my entity library I can do this with reflection, but I still run into the issue that a generic can only make type assurances on explicitly "where T : ISomeInterface" statements. Finally, this model would break down if we have more derived types down the road or types that branch off from interfaces to form new types. Thinking I would need to implement new Data Access Objects for every single type ever made would force changes in the Data Access Layer. That breaks the definition of loose coupling in my mind.

All of this seems to force me back to the question - Can generics be used in a truly loose coupled way? If so, what references can you offer?

Simplified Example:

public interface IEntity
{
    // stuff for state and methods ...
}
public interface IRepository<T> where T : IEntity
{
    void Save(out int id, T obj);
    T Load(int id);
}
public interface IFoo : IEntity
{
    int Id { get; set; }
    //All other IEntities goodness
    //Some new goodness specific to Foo
}
//Concrete Entities:
public class Foo : IFoo
{
    // blah blah
}
public class Foo2 : IFoo
{
    // new blah blah
}

public class FooRepository : IRepository<Foo> //OOPS, Looks like we have settled in on a concrete type!
{

    public void Save(out int id, Foo obj)
    {
        // ADO.NET code to access Sql ...
        id = 1;// this would actually be the result of the Sql insert output parameter
        return;
    }

    public Foo Load(int id)
    {
        Foo foo = new Foo();
        // ADO.Net code to access Sql
        return foo;
    }
}

So how would you deal with code that could handle any IFoo derived object and still be able to return a fully formed concrete type regardless of what programmers do down the road? Is it best to ditch the generic portion and stick with the dependency injection? Any references, guidance, etc. would be great.

Was it helpful?

Solution

With the problem you're running into here, you can always use typeof (or perhaps it's a different operator/method) to get the dynamic type of your object. This way you can always perform checks before running into some casting error.

You can set the concrete type restriction to your top-level type, but that really defeats the purpose of generics.

Otherwise, I don't really see how to overcome your problem. If you use generics, the point is to add loose coupling and generic operations that are agnostic on type. The only way you can retrieve it is you typeof and then recast, catching the edge cases to prevent casting errors. Regarding your question:

Can generics be used in a truly loose coupled way?

I don't quite understand what you mean? Semantically from your question, of course you can. That is in fact one of the purposes of generics.

So how would you deal with code that could handle any IFoo derived object and still be able to return a fully formed concrete type regardless of what programmers do down the road?

This is also quite vague. I could write:

public SomeType method(IFoo obj)
{
...
}

And this would still handle any IFoo. You don't need generics for this. If you want to return the type of whatever you passed in concretely, then:

public T method<T>(IFoo obj) where T:IFoo
{
    return (T)obj;
}

Hope this helps. LMK if I get something wrong.

OTHER TIPS

I have to admit to being a bit confused by your conundrum; I'm not sure what it could be.

A repository that produces concrete types obviously has to know how to create them. Why not create a repository per type such that each implements IRepository<IFoo>? That way you can leave the concrete implementation to your DI container's configuration.

For example, in ninject I'd write something akin to

Bind<IRepository<IFoo>>.To<Foo2Repository>()

to set that up. If you need more fine-grained control, most containers that I know of support some manner of scoping such that the binding is only in force in certain conditions.

Have I misunderstood something, or does this address your concern?

You could define the common stuff in

class BaseFooRepository<TFoo> : IRepository<TFoo> where TFoo : IFoo

and then put the more specific code in

class Foo2Repository : BaseFooRepository<Foo2>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top