views:

444

answers:

3

Hello, I have the following situation in code, which I suspect may be a bit dodgey:

I have a class:

abstract class DataAccessBase<T> : IDataAccess where T : AnotherAbstractClass

This class DataAccessBase also has a static factory method which creates instances of derived classes of itself using an enum value in a which statement to decide which derived type to create:

static IDataAccess CreateInstance(TypeToCreateEnum)

Now, the types derived from DataAccessBase<T> are themselves NOT generic, they specify a type for T:

class PoLcZoneData : DataAccessBase<PoLcZone> // PoLcZone is derived from AnotherAbstractClass

So far I am not sure if this is pushing the limits of good use of generics, but what I am really concerned about is how to access the static CreateInstance() method in the first place:

The way I am doing this at the moment is to simply pass any type T where T : AnotherAbstractClass. In particular I am passing AnotherAbstractClass itself. This allows compilation just fine, but it does seem to me that passing any type to a generic class just to get at the statics is a bit dodgey.

I have actually simplified the situation somewhat as DataAccessBase<T> is the lower level in the inheritance chain, but the static factory methods exists in a middle tier with classes such as PoLcZoneData being the most derived on the only level that is not generic.

What are peoples thoughts on this arrangement?

+1  A: 

I don't think there is anything wrong with that design, specially if you are using the template parameter to specify an implementation detail. What I would suggest would be simply to have the factory function not be static, but just a stand alone. That would be the most clearcut way to go about it for me.

If you want to encapsulate it in some way I would then suggest a namespace, or a naming convention.

Yet another solution would be just hiding what you are currently doing, by defining a type of DataAccessBase maybe like so:

typedef DataAccessBase<AnotherAbstractClass> DataAccessBaseFactory;

This is my least recommended solution, but it leaves the Create function as a static if you absolutely want it to be.

Ramon Zarazua
@killerfox This is c#
Rex M
Ok, in that case I guess the only option is to encapsulate the factory function in a separate class instead of a namespace
Ramon Zarazua
+1  A: 

You are allowed to have a non-generic class of the same name... perhaps something like:

abstract class DataAccessBase<T> : IDataAccess where T : AnotherAbstractClass
{
    ...
}
static class DataAccessBase
{
    public static IDataAccess CreateInstance(TypeToCreateEnum) {...}
}

Now you can use DataAccessBase.CreateInstance without any redundant T. Typically, you might call internal methods on DataAccessBase<T> from DataAccessBase - although I suspect in your scenario you might also need a little reflection / MakeGenericType.

Marc Gravell
A: 

Hi mrlane,

I've ran into a similar problem a while ago ("how to overload static methods") and I solved it with Reflection.

Here's my situation :

1) public abstract class AuditObject<T> : ActiveRecordBase<T> (yes I'm using ActiveRecord) and

2) public class Employee : AuditObject<Employee>

In both of them I define some static Methods, e.g.

public static DataTable GetLookupTable(String where, Int32 topRows)
{
    return doExtremelyCleverStuffToFetchData(where, topRows);
}

(in #2 you need public **new** static or else you get a compiler warning)

As the code is, when I call e.g.

DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100);

...and T is Employee, the static method is not "overriden" i.e. the one that is executed is the method in (1), not (2).

So in (1) I modified the static methods (in this example, GetLookupTable) like this :

public static DataTable GetLookupTable(String where, Int32 topRows)
{
    DataTable tbl = null;

    Boolean hasOverride = hasMethodOverride("GetLookupTable");

    if (hasOverride)
    {
        tbl = invokeStaticMethod<T>(
            "GetLookupTable", new Object[2] { where, topRows })
            as DataTable;
    }
    else
    {
        tbl = doExtremelyCleverStuffToFetchData(where, topRows);
    }

    return tbl;
}

Here's how I find out if the static method exists :

private static Boolean hasMethodOverride(String methodName)
{
    var methodQuery =
        from method in typeof(T).GetMethods(
            BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod)
        where method.Name == methodName
        select method;

    return methodQuery.Count() > 0;
}

And here's how the "override" method is called :

public static Object invokeStaticMethod<T>(String MethodName, Object[] Args)
{
    return typeof(T).InvokeMember(MethodName,
        BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
        null, null, Args);
}

Voila ! When I call DataTable myList = AuditObject<T>.GetLookupTable("inactive = 0", 100); and T is Employee, I get results from the static method defined in the Employee class.

Hope this helps,

Dimitris

Dimitris Andrakakis