【问题标题】:How do I create a C# generic method that takes in one generic type and returns another generic type?如何创建一个接受一种泛型类型并返回另一种泛型类型的 C# 泛型方法?
【发布时间】:2016-12-09 10:39:23
【问题描述】:

如何创建一个接受一种泛型类型并返回另一种泛型类型的 C# 泛型方法?我如何获得 T 的实际类型,以便我可以将我的新类型作为通用 T 类型返回。

基本上,我想实现类似这个示例代码的东西,其中if/else 逻辑在类型之间转换。如果有更好的方法来做同样的事情,比如使用 Func,请告诉我。任何帮助,将不胜感激。谢谢。

编辑: 好的,这几乎正是我想要做的。 (只是类型不同)我不认为“Convert.ChangeType”会起作用,因为我使用的是自定义类型。

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;
}

可能的用例:

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

【问题讨论】:

  • 你能展示你正在尝试做什么的例子吗?...编译器也不能推断出通用返回类型。如果泛型仅用于返回,则必须在调用方法时指定它。
  • 您可能对Convert.ChangeType感兴趣
  • .Net中还有很多Convert方法,用Convert.
  • 我会提供更多关于您的实际目标的背景信息。我不确定泛型是否适合您的情况....

标签: c# generics methods


【解决方案1】:

你可以试试这个:

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);
}

【讨论】:

    【解决方案2】:

    好吧,如果您对类型一无所知,那么您可以做的最好的事情基本上就是使用 Rob 和 Rabban 建议的 ChangeType 方法:

    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));
        }
    }
    

    请注意,如果您尝试使用具有不兼容值和类型的方法,这将在运行时引发异常:

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

    因此,使用这样的泛型可能不是解决您正在尝试做的任何事情的最佳方式。

    【讨论】:

    • ChangeType 不起作用,因为我使用的是自定义类型。我更新了我的代码示例以反映我正在处理的实际代码。
    • 泛型的主要目的是提供编译时类型安全...您有类似工厂方法的东西,它试图基于传递给方法。然后工厂方法本身应该负责了解如何根据您的特定逻辑创建新实例。您不能真正使这种转换逻辑“通用”。
    • 感谢您的观察,您对我可以这样做的替代方法有什么建议吗?我现在处于精神障碍中。谢谢
    • 就像我说的,实现您的 Convert 方法以根据您的逻辑执行转换。在方法中创建类型 T 的实例,并根据输入类型将其属性设置为适当的值。所有不属于通用 ICustomType 接口的属性都必须使用反射进行设置。在给定 TypeB 的实例的情况下,只有您应该知道如何创建 TypeA 的实例。编译器当然不会。
    【解决方案3】:

    好的,休息后我回来解决了我的问题。事实证明,我所要做的就是将我的类型作为约束接口传回,然后在我返回它之前将其转换为泛型 T。就是这样,一切正常。谢谢大家的帮助。

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-12
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 2019-12-06
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多