alejandromxl
alejandromxl

Reputation: 11

Generic and defined types in one class

Is it possible to have generic types and non-generic types in one class??

I have a class in which I have to manage different types but I don't know exactly what I'm going to receive, I though about using generics but I have not found a way for doing this.

This is what I am trying to do

int commandCode;
<T> arg1;
<T> arg2;
<T> arg3;

I have to read 4 string lines out of a text file, and try to parse those lines into

  1. int
  2. float
  3. boolean
  4. leave it as a string

(First trying to parse it to 1, if not possible to 2, if not possible to 3, if not possible to 4.)

And after knowing what type is each argument, define each variable with the its respective type

For instance with a text file with

I would have an object with

And that would happen for any combination possible for arg1 to arg3.

Upvotes: 1

Views: 88

Answers (2)

Oliver
Oliver

Reputation: 45071

If you have variable types depending on the data you read (like in your case) it doesn't make much sense to use generics. Even if you take @Spontifixus approach you are not able to put all the created elements in one List<T>, cause due to the different types used in each object you need for each combination your own List<T>. Also if you later in code like to work with all the arguments, you need to query for each generic type to know how to read the desired value out of the current instance.

If you still think you need generic types (in this case) you can help yourself by using a generic class a creator method and a normal interface:

public interface ICommand
{
    int CommandCode { get; set; }
    object Argument1 { get; }
    object Argument2 { get; }
    object Argument3 { get; }
}

public static class Command
{
    public static Command<T1, T2, T3> Create<T1, T2, T3>(int code, T1 arg1, T2 arg2, T3 arg3)
    {
        return new Command<T1, T2, T3>(code, arg1, arg2, arg3);
    }
}

public class Command<T1, T2, T3> : ICommand
{
    public Command(int code, T1 arg1, T2 arg2, T3 arg3)
    {
        CommandCode = code;
        Argument1 = arg1;
        Argument2 = arg2;
        Argument3 = arg3;
    }

    public int CommandCode { get; set; }
    public T1 Argument1 { get; set; }
    public T2 Argument2 { get; set; }
    public T3 Argument3 { get; set; }

    object ICommand.Argument1
    {
        get { return Argument1; }
    }

    object ICommand.Argument2
    {
        get { return Argument2; }
    }

    object ICommand.Argument3
    {
        get { return Argument3; }
    }
}

By using this approach you can create a instance through type inference by calling the creator method and put all of them in one list:

var commands = new List<ICommand>();
var myCommand = Command.Create(3, 4f, true, "hello world");
var commands.Add(myCommand);

Now you got your generic objects in one list, but how do you work with this list? At last you're going all the time using the ICommand interface and stick to the object, making the generics useless. But maybe you don't think so and this approach might help.

Upvotes: 0

Rune FS
Rune FS

Reputation: 21742

If I understnad you correctly you can only determine the actual type at runtime. In that csae generics won't help you much since any type argument needs to be resolved at compile time therefor you need to use reflection in some manner. Below is a factory that could be extended to support your needs. You might or might not need 16 different methods depending on how many subclasses you have in reality (you'd need one for each subclass with the below approach) you could also skip the Create method and select the appropriate class/constructor directly

public class Command {

   public static Command Create(string[] textLines) {
     var args = textLines.Select(l => parseLine(l));
     var argTypes = args.Select(a => a.GetType().ToArray();
     return (Command)typeof(Command).GetMethod("Create",argTypes).Invoke(null,args);
   }

   public static Command Create(int commandType,
                                bool IsSponk,
                                int count, 
                                string description){
       return new CommandType1(commandType,
                               IsSponk,
                               count,
                               description);
   }
   private class CommandType1 : Command {
       public CommandType1(int commandType, bool IsSponk, int count, string description){
            ....
       }
   }
}

Upvotes: 1

Related Questions