tags:

views:

244

answers:

4

Bellow is simplified version of the code I have:

public interface IControl<T>
{
    T Value { get; }
}

public class BoolControl : IControl<bool>
{
    public bool Value
    {
        get { return true; }
    }
}

public class StringControl : IControl<string>
{
    public string Value
    {
        get { return ""; }
    }
}
public class ControlFactory
{
    public IControl GetControl(string controlType)
    {
        switch (controlType)
        {
            case "Bool":
                return new BoolControl();
            case "String":
                return new StringControl();
        }
        return null;
    }
}

The problem is in GetControl method of ControlFactory class. Because it returns IControl and I have only IControl<T> that is a generic interface. I cannot provide T because in Bool case it's going to bool and in String case it's going to be string.

Any idea what I need to do to make it work?

+3  A: 

Just derive IControl<T> from IControl.

public interface IControl<T> : IControl
{
    T Value { get; }
}

UPDATE

If I missunterstood you, and you don't want a non-generic interface, you will have to make the method GetControl() generic, too.

public IControl<T> GetControl<T>()
{
    if (typeof(T) == typeof(Boolean))
    {
        return new BoolControl(); // Will not compile.
    }
    else if (typeof(T) == typeof(String))
    {
        return new StringControl(); // Will not compile.
    }
    else
    {
        return null;
    }
}

Now you have the problem that the new controls cannot be implicitly casted to IControl<T> and you would have to make this explicit.

public IControl<T> GetControl<T>()
{
    if (typeof(T) == typeof(Boolean))
    {
        return new (IControl<T>)BoolControl();
    }
    else if (typeof(T) == typeof(String))
    {
        return (IControl<T>)new StringControl();
    }
    else
    {
        return null;
    }
}

UPDATE

Changed the cast from as IControl<T> to (IControl<T>). This is prefered because it will cause an exception if there is a bug while as IControl<T> silently returns null.

Daniel Brückner
+2  A: 
public IControl<T> GetControl<T>()
{
    switch (typeof(T).Name)
    {
        case "Bool":
            return (IControl<T>) new BoolControl();
        case "String":
            return (IControl<T>) new StringControl();
    }
    return null;
}

Update; corrected a couple of errors in the code. Heres a call to get a class:

IControl<bool> boolControl = GetControl<bool>();
Fredrik Mörk
@Vadim - I would strongly advise you to use Daniel's solution, where he's comparing types rather than using strings. Using the name of the type is more error prone.
Jon B
@Jon B: you are right; comparing the types will provide more robust code. I simply updated Vadim's original code to work. Daniel's approach is the better way to go.
Fredrik Mörk
A: 

You would have to make it:

public IControl<T> GetControl<T>(string controlType) {}

(At which point the controlType string is redundant)

You can't simply return an IControl without specifying a type.

Jon B
A: 

The return type has to be generic, since, well, it is. Think of how you would use this. Returning a strongly typed object obviates the need for a generic factory method.

Even if you could do it, what's the gain of

IControl<bool> boolControl = controlFactory.GetControl("bool");

or, the one that would work,

IControl<bool> boolControl = controlFactory.GetControl<bool>("bool");

over a specific

IControl<bool> boolControl = controlFactory.GetBoolControl("bool");

Either way, you have the switch () at the client side. Either return an object, or have a non-typed IControl interface.

Stu