dek
dek

Reputation: 85

How do I create a C# generic method that takes in one generic type and returns another generic type?

How do I create a C# generic method that takes in one generic type and returns another generic type? How do i get the actual Type of T so that i can return my new type as that generic T type.

Basically, I want to achieve something like this sample code where the if/else logic converts between types. If there's a better way to do the same thing like with using Func please let me know. Any help would be appreciated. thank you.

EDIT: OK this is almost exactly what I want to do. (Just the types are different) I don't think "Convert.ChangeType" would work because I am using custom types.

public interface ICustomType{}    
public struct TypeA : ICustomType {}
public struct TypeB : ICustomType {}
public struct TypeC : ICustomType {}

public static T Convert<T>(ICustomType input) where T : ICustomType
{
    var output = default(T);

    if (output is TypeA)
    {
        if (input is TypeA)
        {
            output = input;
        }
        else if (input is TypeB)
        {                
            output = CustomTypeB_ToTypeA_Converter(input);
        }
        else if (input is TypeC)
        {
            output = CustomTypeC_ToTypeA_Converter(input);
        }
    }
    else if (output is TypeB)
    {
        if (input is TypeA)
        {
            output = CustomTypeA_ToTypeB_Converter(input);
        }
        else if (input is TypeB)
        {                
            output = input;
        }
        else if (input is TypeC)
        {
            output = CustomTypeC_ToTypeB_Converter(input);
        }
    }
    else if (output is TypeC)
    {
       // same pattern as above
    }
    return output;
}

possible use case:

TypeA a = 45;
TypeB result = Convert<TypeB>(a);

Upvotes: 1

Views: 163

Answers (3)

dek
dek

Reputation: 85

Ok after a break I came back and was able to solve my problem. It turns out all i had to do was pass my type back as the constraint interface and then cast it to the generic T before i return it. And that's it, everything worked. Thanks all for the help.

public interface ICustomType{}    
public struct TypeA : ICustomType {}
public struct TypeB : ICustomType {}
public struct TypeC : ICustomType {}

public static T Convert<T>(ICustomType input) where T : ICustomType
{
    var output = default(T);

    if (output is TypeA)
    {
        if (input is TypeA)
        {
            output = (T)input;
        }
        else if (input is TypeB)
        {  
            // first assign my type to ICustomType interface
            ICustomType typeA =  CustomTypeB_ToTypeA_Converter(input);
            // then cast that interface to the generic T before you return it             
            output = (T)typeA;
        }
        else if (input is TypeC)
        {  
            // first assign my type to ICustomType interface
            ICustomType typeC =  CustomTypeC_ToTypeA_Converter(input);
            // then cast that interface to the generic T before you return it             
            output = (T)typeC;
        }
    }
    else if (output is TypeB)
    {
        // same pattern as above
    }
    else if (output is TypeC)
    {
       // same pattern as above
    }
    return output;
}

Upvotes: 0

Pedro Perez
Pedro Perez

Reputation: 932

You can try this:

public static void Main()
{
    var str = "1.0";

    decimal result = Convert(str, ConvertToDecimal);
}

public static decimal ConvertToDecimal(string str)
{
    return decimal.Parse(str);
}

public static TOut Convert<TIn, TOut>(TIn item, Func<TIn, TOut> f)
{
    return f(item);
}

Upvotes: 1

mm8
mm8

Reputation: 169200

Well, if you don't know anything about the types the best thing you could do is basically to use the ChangeType method as suggested by Rob and Rabban:

public static class Program
{
    public static void Main()
    {
        string s = "1";
        double d = Convert<string, double>(s);
        Console.WriteLine(d);
    }

    public static TOut Convert<TIn, TOut>(TIn text)
    {
        return (TOut)System.Convert.ChangeType(text, typeof(TOut));
    }
}

Note that this will throw an exception at runtime if you try to use the method with incompatible values and types though:

    public static void Main()
    {
        string s = "T";
        //THIS WILL THROW A FORMATEXCEPTION
        double d = Convert<string, double>(s);
        Console.WriteLine(d);
    }

So using generics like this is probably not the best way to solve whatever you are trying to do.

Upvotes: 0

Related Questions