Click here to Skip to main content
15,884,629 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
This is one case where code really is worth a thousand words. The code that follows does not compile. I hope it is close enough to show what I am trying to do.

I don't see anything conceptually wrong with what I am trying to do but seem to be in a complete mix-up with syntax. Of course, if what I am trying to do is fundamentally a bad idea, I am always willing to learn from greater minds.

Hopefully, it goes without saying that this is a contrived example, lacking any error checking. I'm just trying to show the pattern I am trying to implement.

public interface IReturnsValue<T>
{
    void SetValues( List<T> listOfValues );
    T NextValue { get; }
}

public class IntegerReturner : IReturnsValue<int>
{
    public void SetValues( List<int> listOfValues ) { _values = listOfValues; }
    public int NextValue => _values[ _indexOfNextValue++ ];
    private int _indexOfNextValue = 0;
    private List<int> _values = null;
}

public class DoubleReturner : IReturnsValue<double>
{
    public void SetValues( List<double> listOfValues ) { _values = listOfValues; }
    public double NextValue => _values[ _indexOfNextValue++ ];
    private int _indexOfNextValue = 0;
    private List<double> _values = null;
}

public class ValueReturnerFactory
{
    public IReturnsValue<T> CreateValueReturner<T>( string name )
    {
        if( name == "IntegerReturner" )
            return new IntegerReturner();
        if( name == "DoubleReturner" )
            return new DoubleReturner();
        throw new ArgumentException();
    }
}

class Program
{
    static void Main( string[] args )
    {
        ValueReturnerFactory factory = new ValueReturnerFactory();
        IReturnsValue<T> firstValueReturner = factory.CreateValueReturner<int>( "IntegerReturner" );
        IReturnsValue<T> secondValueReturner = factory.CreateValueReturner<double>( "DoubleReturner" );
    }
}


What I have tried:

Every combination of generic code type parameter I can think of. :(
Posted
Updated 14-Nov-18 23:59pm
v2

1 solution

It doesn't work as the compiler can't check if T is always an int when using IntegerReturner etc. For example, the following call would be valid according to the method signature:
C#
factory.CreateValueReturner<bool>("IntegerReturner")

where it would have to return an IReturnsValue<int> as an IReturnsValue<bool>.

You can "take over responsibility" and cast in the factory. So:
C#
public IReturnsValue<T> CreateValueReturner<T>(string name)
{
    if (name == "IntegerReturner")
        return (IReturnsValue<T>)new IntegerReturner();
    if (name == "DoubleReturner")
        return (IReturnsValue<T>)new DoubleReturner();
    throw new ArgumentException();
}

you will then get a runtime exception if the types do not match.

You also have to specify the type in the Main method as T isn't defined here (or use var of course):
C#
IReturnsValue<int> firstValueReturner = factory.CreateValueReturner<int>("IntegerReturner");

IReturnsValue<double> secondValueReturner = factory.CreateValueReturner<double>("DoubleReturner");

It's hard to say if there are better ways to implement this, it depends on the rest of the code and personal preference. If it was me, I would consider if I could get rid of the name and select the class to instantiate from the type of T - then you can't have a situation where T and name do not match. The factory method can be something like this:
C#
public IReturnsValue<T> CreateValueReturner<T>()
{
    if (typeof(T) == typeof(int))
        return (IReturnsValue<T>)new IntegerReturner();
    if (typeof(T) == typeof(double))
        return (IReturnsValue<T>)new DoubleReturner();
    throw new ArgumentException();
}
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900