C# 如何将动态类传递给泛型函数?

C# 如何将动态类传递给泛型函数?,c#,class,generics,dynamic,ml.net,C#,Class,Generics,Dynamic,Ml.net,我想制作一个用于web应用程序的机器学习api,字段名将与其数据类型一起传递给api 目前,我正在使用此答案中提供的代码在运行时创建一个类: 当我需要调用ML.NET PredictionFunction时,问题就出现了,我无法传递泛型函数的类型,因为它们是在运行时生成的。 我尝试使用反射调用它,但是它似乎无法找到函数 注意:目前ML.NET的文档正在更新为0.9.0,因此不可用 我尝试的是(最低限度): 完整(修订和修剪)来源(更多上下文): Program.cs namespace Gene

我想制作一个用于web应用程序的机器学习api,字段名将与其数据类型一起传递给api

目前,我正在使用此答案中提供的代码在运行时创建一个类:

当我需要调用ML.NET PredictionFunction时,问题就出现了,我无法传递泛型函数的类型,因为它们是在运行时生成的。 我尝试使用反射调用它,但是它似乎无法找到函数

注意:目前ML.NET的文档正在更新为0.9.0,因此不可用

我尝试的是(最低限度):

完整(修订和修剪)来源(更多上下文): Program.cs

namespace Generic {
  class Program {
    public class GenericData {
      public float SepalLength;
      public float SepalWidth;
      public float PetalLength;
      public float PetalWidth;
    }
    public class ClusterPrediction {
      public uint PredictedLabel;
      public float[] Score;
    }

    static void Main(string[] args) {
      List<Field> fields = new List<Field>() {
                new Field(){ name="SepalLength", type=typeof(float)},
                new Field(){ name="SepalWidth", type=typeof(float)},
                new Field(){ name="PetalLength", type=typeof(float)},
                new Field(){ name="PetalWidth", type=typeof(float)},
            };
      var generatedType = GenTypeBuilder.CompileResultType(fields);

      var mlContext = new MLContext(seed: 0);
      TextLoader textLoader = mlContext.Data.TextReader(new TextLoader.Arguments() {
        Separator = ",",
        Column = new[]
        {
          new TextLoader.Column("SepalLength", DataKind.R4, 0),
          new TextLoader.Column("SepalWidth", DataKind.R4, 1),
          new TextLoader.Column("PetalLength", DataKind.R4, 2),
          new TextLoader.Column("PetalWidth", DataKind.R4, 3)
        }
      });
      IDataView dataView = textLoader.Read(Path.Combine(Environment.CurrentDirectory, "Data", "flowers.txt"););

      var pipeline = mlContext.Transforms
        .Concatenate("Features", "SepalLength", "SepalWidth", "PetalLength", "PetalWidth")
        .Append(mlContext.Clustering.Trainers.KMeans("Features", clustersCount: 3));
      var model = pipeline.Fit(dataView);

      Type[] typeArgs = { generatedType, typeof(ClusterPrediction) };
      object[] parametersArray = { mlContext }; // value

      MethodInfo method = typeof(TransformerChain).GetMethod("MakePredictionFunction");
      if (method == null) { // Using PredictionFunctionExtensions helps here
        Console.WriteLine("Method not found!");
      }
      MethodInfo generic = method.MakeGenericMethod(typeArgs);
      var temp = generic.Invoke(model, parametersArray);

      var prediction = temp.Predict(new GenericData {SepalLength = 5.6f, SepalWidth = 2.5f,
                                                     PetalLength = 3.9f, PetalWidth = 1.1f});
    }
  }
}
命名空间泛型{
班级计划{
公共类泛型数据{
公共浮动分离长度;
公共浮动分离宽度;
公众漂浮长度;
公众漂浮花瓣宽度;
}
公共类聚类预测{
公共uint预测标签;
公众浮动[]分;
}
静态void Main(字符串[]参数){
列表字段=新列表(){
新字段(){name=“separalength”,type=typeof(float)},
新字段(){name=“SepalWidth”,type=typeof(float)},
新字段(){name=“PetalLength”,type=typeof(float)},
新字段(){name=“PetalWidth”,type=typeof(float)},
};
var generatedType=GenTypeBuilder.CompileResultType(字段);
var mlContext=新的mlContext(种子:0);
TextLoader TextLoader=mlContext.Data.textleader(新的TextLoader.Arguments(){
分隔符=“,”,
列=新[]
{
新的TextLoader.Column(“separalength”,DataKind.R4,0),
新的TextLoader.Column(“SepalWidth”,DataKind.R4,1),
新的TextLoader.Column(“PetalLength”,DataKind.R4,2),
新的TextLoader.Column(“PetalWidth”,DataKind.R4,3)
}
});
IDataView dataView=textLoader.Read(Path.Combine(Environment.CurrentDirectory,“Data”,“flowers.txt”);
var pipeline=mlContext.Transforms
.连接(“特征”、“分离长度”、“分离宽度”、“花瓣长度”、“花瓣宽度”)
.Append(mlContext.Clustering.Trainers.KMeans(“Features”,clustersunt:3));
var模型=pipeline.Fit(数据视图);
Type[]typeArgs={generatedType,typeof(ClusterPrediction)};
对象[]参数数组={mlContext};//值
MethodInfo method=typeof(TransformerChain).GetMethod(“MakePredictionFunction”);
如果(method==null){//使用PredictionFunctionExtensions在这里有帮助
WriteLine(“找不到方法!”);
}
MethodInfo generic=method.MakeGenericMethod(typeArgs);
var temp=generic.Invoke(模型,参数数组);
var预测=温度预测(新的一般数据{separalength=5.6f,separawidth=2.5f,
花瓣长度=3.9f,花瓣宽度=1.1f});
}
}
}

尝试在IDataView中读取测试数据,然后将IDataView传递给model.Transform()


这应该将分数和PredictedLabel作为单独的列插入测试数据中

似乎,在尝试对
MakePredictionFunction
进行反思时,您将
TransformerChain
类型(可实例化的泛型类型)与静态类
TransformerChain
混淆了

但即使反思
TransformerChain
也不会成功,因为
MakePredictionFunction
不是这种类型声明的方法。相反,
MakePredictionFunction
是在静态类
PredictionFunctionExtensions
⁽¹⁾.

因此,要获取
MakePredictionFunction
的MethodInfo,请尝试以下操作:

MethodInfo method = typeof(PredictionFunctionExtensions).GetMethod("MakePredictionFunction");


⁽¹⁾
我不能100%确定PredictionFunctionExtensions驻留在哪个命名空间中。搜索ML.NET 0.9.0 API文档时,它似乎位于Microsoft.ML.Runtime.Data命名空间中。但是尝试访问MakePredictionFunction的实际文档页面目前只会导致404错误,因此该信息可能不准确(我不是ML.NET用户,因此无法验证):-(

我不确定问题到底是什么。问题是
方法==null
即在
TransformerChain
上找不到该方法吗?请提供-清楚地说明
TransformerChain
(无论是什么)没有你正在寻找的方法…但是没有真正的样本,你无法知道为什么。@Paprika你现在已经展示了大量不相关的代码。你应该展示一个最小的可复制的示例。不再展示重现问题所需的内容。然而,正如Kevin Grosse指出的,
MakePredictionFunction
是一个e可应用于
ITransformer
实例的xtension方法,并且
TransformerChain
正在实现
ITransformer
。请注意,此扩展方法不是
TransformerChain
类型定义的一部分,因此在查询
TransformerChain
类型时,您也会得到
null
。如果您需要扩展方法的MethodInfo,您需要查询声明扩展方法的类型。如果是
MakePredictionFunction
,您需要查询
PredictionFunctionExtensions
type…@elgonzo,您可能应该将注释转换为答案…或者我们应该将其作为副本关闭“通过反射调用扩展”(like)这似乎是一个很好的答案,它允许我完全不需要生成类,直接从IDataView获取数据。谢谢!
MethodInfo method = typeof(PredictionFunctionExtensions).GetMethod("MakePredictionFunction");