1

There is a generic function

Result<T> F<T>(int id) { .... }
void F2<T>(Result<T> r) { ... }

and there is a list of string (read from appsettings.json).

List<(string, int)> s = new List<(string, int)> {
    ("int", 10),
    ("string", 21),
    ("DateTime", 31),
    ("int", 20)
    ... }

How to call F with the items from the string list?

foreach (var (t, id) in s)
{
    var result = F<???>(id); // need the type from t here
    F2<???>(result);
}

Why I asked this:

The original code has a list of

F<int>(123); 
F<string>(345); 
F<int>(32); 
F<Othertype>(32);
... many more ...

in the source code. And it needs to be updated/added from time to time. I'm trying to move it to the config file so I don't need to modify the code and recompile the code everytime.

ca9163d9
  • 27,283
  • 64
  • 210
  • 413
  • Why not just use the type parameter to define the type of the parameters you want to input ? `void F(IEnumerable items) { access items here }` – jdewerth Mar 18 '20 at 01:02
  • 1
    Since you can't do this (not without turning it into a `Type` and using reflection), can I ask what your ultimate goal is? What does `F` do? – ProgrammingLlama Mar 18 '20 at 01:04
  • If you can start from actual types (and not `int`/`string`) and want very data-controlled solution look at https://stackoverflow.com/questions/232535/how-do-i-use-reflection-to-call-a-generic-method and https://stackoverflow.com/questions/2933221/can-you-get-a-funct-or-similar-from-a-methodinfo-object which should give you `Action` at the end... Probably put in dictionary as suggested by all answers. – Alexei Levenkov Mar 18 '20 at 01:58

3 Answers3

3

The short answer is F<???> is not possible. All that stuff occurs in compile time. The closest situation is use "dynamic" but, you have the same problem. You don't have access to the "Type elements" directly, only by reflection.

var type = Type.GetType("System.Int32");

var obj = Activator.CreateInstance(typeof(F<>).MakeGenericType(type));

As you see, you must store the types as fullname with namespaces, but this is the way.

The other way is use a Dictionary<string, F<T>> but that forces you to update the map everytime you add a new type to be managed. (If you use Dictionary<string, Type> you have the same problem as with the first option).

You must considerate that if you want to call methods, properties and everything you will have to do it with reflection

Edit: The OTP solution is write code dynamically, compile it and load it in runtime (DON'T DO THIS)

This bring me to the question, what are you trying to do? This sounds like a overthought of a simple problem.

DrkDeveloper
  • 939
  • 7
  • 17
  • I'm improving a legacy program that processes some data with the heterogeneous data type - `T` in the question. – ca9163d9 Mar 18 '20 at 01:57
  • @ca9163d9 Then I can't help you more without read the code of the instantiation and the usage. But the only options (that I can remember) are those I pointed. – DrkDeveloper Mar 18 '20 at 02:00
2

I would create a dictionary to map from string to Type;

var mappings = new Dictionary<string,Type>(){ { "int", typeof(int) }, ... };

Then I'd modify your F<T>() so you can easily call a non-generic version;

public static void F<T>(int value) => F(typeof(T), value);
public static void F(Type type, int value){
   ...
}

The remainder should now be obvious;

Dictionary<string, int> config = ...
foreach (var t in config)
{
    F(mappings[t.Key], t.Value);
}
Jeremy Lakeman
  • 9,515
  • 25
  • 29
2
void F<T>(int id) { .... }
void F(string typeName , int id) 
{ 
    if ( typeName == "int" )
    {
         F<Int>(id)
    }else if ( typeName == "string")
    {
         F<string>(id)
    }
    //... all type
}

foreach (string t in s)
{
    F(t,val);
}
TimChang
  • 2,249
  • 13
  • 25