【问题标题】:How to pass a type parameter of a generic function from string value?如何从字符串值传递泛型函数的类型参数?
【发布时间】:2020-03-18 00:56:28
【问题描述】:

有一个通用函数

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

还有一个字符串列表(从appsettings.json读取)。

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

如何使用字符串列表中的项目调用F

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

我为什么问这个:

原代码有一个列表

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

在源代码中。并且需要不时更新/添加。我正在尝试将其移动到配置文件中,因此我不需要每次都修改代码并重新编译代码。

【问题讨论】:

  • 为什么不直接使用type参数来定义要输入的参数的类型呢? void F&lt;T&gt;(IEnumerable&lt;T&gt; items) { access items here }
  • 既然你不能做到这一点(不能不把它变成Type 并使用反射),请问你的最终目标是什么? F 是做什么的?
  • 如果您可以从实际类型开始(而不是int/string)并且想要非常受数据控制的解决方案,请查看stackoverflow.com/questions/232535/…stackoverflow.com/questions/2933221/…,这应该会给您Action&lt;int&gt;结束...可能按照所有答案的建议放入字典中。

标签: c#


【解决方案1】:

简短的回答是F&lt;???&gt; 是不可能的。所有这些都发生在编译时。最接近的情况是使用“动态”,但是,你有同样的问题。您无法直接访问“类型元素”,只能通过反射访问。

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

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

如您所见,您必须将类型存储为带有命名空间的全名,但这就是方式。

另一种方法是使用Dictionary&lt;string, F&lt;T&gt;&gt;,但这会强制您在每次添加要管理的新类型时更新地图。 (如果您使用Dictionary&lt;string, Type&gt;,您会遇到与第一个选项相同的问题。

你必须考虑到如果你想调用方法、属性和所有你必须用反射来做的事情

编辑:OTP 解决方案是动态编写代码,编译并在运行时加载(不要这样做)

这让我想到了一个问题,你想做什么?这听起来像是对一个简单问题的过度思考。

【讨论】:

  • 我正在改进一个遗留程序,该程序处理一些具有异构数据类型的数据 - 问题中的T
  • @ca9163d9 那么如果不阅读实例化的代码和使用方法,我将无法为您提供更多帮助。但唯一的选择(我记得的)是我指出的那些。
【解决方案2】:

我会创建一个字典来从string 映射到Type

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

然后我会修改您的F&lt;T&gt;(),以便您可以轻松调用非通用版本;

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

其余部分现在应该很明显了;

Dictionary<string, int> config = ...
foreach (var t in config)
{
    F(mappings[t.Key], t.Value);
}

【讨论】:

    【解决方案3】:
    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);
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-05
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      • 1970-01-01
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-17
      相关资源
      最近更新 更多