tags:

views:

105

answers:

5

Hi,

I wrote this method:

    public IGamePlugin[,] GetTable<T>()
    {
        Type t = typeof(T);

        if (t is IFixedElement)
        {
            return fixedElements;
        }
        else if (t is IFixedTile)
        {
            return fixedTiles;
        }
        else
        {
            throw new NotSupportedException("Type:" + t.ToString() + " is not supported");
        }
    }

And I'm quite unsure if it is not wrong usage of generics. I like it better than using a simple parameter (string or maybe Type) because the syntax is clear on the calling side.

What do you think?

+4  A: 

This really should be two separate functions, GetElementsTable and GetTilesTable.

To answer your question, it definitely is abuse of generics the way you've done it. But you're right that using a parameter is also bad.

Ben Voigt
Why is using a parameter bad?
Marc Gravell
Using a parameter can be a fine solution, it depends on the situation.
MrFox
Because a function should have one responsibility. Here the function does two totally different things depending on the generic type, with no shared code whatsoever between the paths, not even conceptually, hence they belong in separate functions. Using a parameter instead of a generic type doesn't solve the violation of the single responsibility principle.
Ben Voigt
@Ben - I can certainly agree with you on that, but the generic vs parameter debate feels (IMO) an orthogonal concern to that. I'm not quite sure why you claim it would be "bad".
Marc Gravell
Yes, I can separate it. I wanted to have it in one function because the method GetList is part of interface used for communication of plugins with main app. I wanted to keep the interface simple but I guess it's better to have two functions with clear names.
MartyIX
@Marc: Does something in my answer suggest to you that I think one of generic vs parameter way of packing two operations into one function is less bad than the other? I called one *abuse* and the other *also bad*.
Ben Voigt
Ah right; it might have been the way I was reading it. If you mean "using this same approach, but with a parameter would *still* be bad", then fine - we're in accord. Perhaps because of it being a sentence by itself, I read it as "no matter the *what*, passing the type in as the parameter here would be bad". Probably just me reading things poorly on a Sunday evening ;p
Marc Gravell
Two seperate functions will be very bad for exensibility, also in most of these cases you need to do some stuff for every type, seperate functions will lead to much duplicate code.
MrFox
+2  A: 

It is an unusual usage, for sure; it doesn't really use the T, except for typeof(T) . I can see how it may be more useful if you were combining that with generic constraints, but "as is" I'd be tempted to pass a Type instance in as the argument.

BTW, the usage of is is incorrect here; you are testing whether the Type type implements IFixedTile etc, which will never be true (unless you are doing something very unusual); you probably mean to test whether the type represented implements the interface. Perhaps IsAssignableFrom?

Marc Gravell
In this example I wanted to test whether T really is IFixedElement. I didn't want objects that implement IFixedElement interface.
MartyIX
@MartyIX - you miss my point; `t` is an object of type `Type`, and **never** implements those interfaces. I've clarified in an update...
Marc Gravell
@MartyIX: Then the test would be `if (typeof(T) == typeof(IFixedElement))`... but I feel two functions is even better yet.
Ben Voigt
I see now. How can I check if T is IFixedElement interface then?
MartyIX
@MartyIX - if you mean **is exactly** `IFixedElement`, then `t == typeof(IFixedElement)` should do it. If you mean "is a type that implements `IFixedElement`", then `typeof(IFixedElement).IsAssignableFrom(t)`
Marc Gravell
@Marc: Thanks you!
MartyIX
A: 

It depends, are you going to do anything else with the classes? It seems like a bit of a waste to define interfaces and classes just to make a choice. If you only need to choose between states, use enums:

public enum ElementType
{
    FixedElements, FixedTiles
}

Then you can ask for an ElementType argument.

MrFox
I don't see the benefit of `GetTable(ElementType.FixedTiles)` over `GetTilesTable()`. Maybe if this was a virtual method and the set of possible types varied, but not for this question.
Ben Voigt
+1  A: 

I agree with Ben Voigt - it should be two different methods.

But actually your code won't work because t is of Type object ant it is not implementing any of your interfaces. Instead you should use t.GetInterface("IFixedElement") != null

Andrew Bezzub
@Andrew: Marc has already pointed it out. Thanks for the method!
MartyIX
A: 

It looks like you're returning a specific 2D array depending on the type provided. So the essential parameter you're looking for is not the actual object being passed, but the type. If that's the case, why not simply declare a Dictionary<Type, IGamePlugin[,]> and get the value you need from the dictionary?

I'm thinking like:

// declare this somewhere earlier in the code...
var plugInDictionary = new Dictionary<Type, IGamePlugin[,]>()
{
  {typeof(IFixedElement), fixedElements},
  {typeof(IFixedTile), fixedTiles} 
}
...

// where you would normally call the method GetTable call this instead...
var myGamePlugIn = plugInDictionary[typeof(myObject)];

The advantage of using a dictionary is that it's more dynamic than using an if-block, especially since it accomodates DI more readily than an if-block. What that means is that for instance, you can register the setup above to a config file and actually have to write just a couple of lines of code - the rest is handled by the DI framework. Not that I'm advocating DI for your project, but this was the one example that came to mind for illustrating code flexibility.

code4life
Thanks for a solution! What does it mean "DI"?
MartyIX
@MartyIX: Dependency Injection
Peter Kelly