将Func <t,iconvertible =“”>的结果转换为lambda表达式中的int

时间:2017-07-06 10:20:42

标签: c# linq generics casting functional-programming

我正在抽象一些代码,并遇到了将Func的结果转换为整数以进行比较的问题。

我有一个功能:

public static IConvertible GetIllnessRateByParity(IEnumerable<ILLNESS_OBJECT> pItems, int pParity, Func<ILLNESS_OBJECT, IConvertible> pSelector)
    {
        var filtered = pItems.Where(a => a.Parity == pParity);
        return Math.Round(filtered.Count(a => Convert.ToInt32(pSelector(a)) == 1) / (double)GetBirthCountByParity(pItems, pParity), 2);
    }

public class ILLNESS_OBJECT
{
    public int ID { get; set; }
    public DateTime Day { get; set; }
    public int Parity { get; set; }
    public int Afterbirth { get; set; }
    public int OvaryInfection { get; set; }
    etc...
}

计算一组数据中特定疾病的发生率。要分析的疾病通过选择器输入,该选择器从ILLNESS_OBJECT对象中选择IConvertible值。

我这样称呼方法:

GetIllnessRateByParity(data, 1, a => a.AfterBirth)

数据是具有非空值的IEnumerable。

该方法在Convert.ToInt32(pSelector(a))部分抛出InvalidCastException而没有明确指出此强制转换失败的原因,是否有人可以向我解释?我的印象是pSelector(a)返回一个与int转换兼容的IConvertible值,对吧?任何帮助将不胜感激!

编辑:异常消息: 类型&#39; System.InvalidCastException&#39;的例外情况发生在CONFIDENTIAL.CLASS.dll但未在用户代码中处理

消息:指定的演员表无效。

2 个答案:

答案 0 :(得分:2)

最后一个参数叫做pSelector,但它实际上并不是一个选择器。

它只是返回一个值(int,float ...),而实际选择是由lab方法中的labmda完成的:

filtered.Count(a => Convert.ToInt32(pSelector(a)) == 1)

因此pSelector将返回某种数据类型的值,然后您依赖于能够将其转换为int32。

但是你只需要将它与1进行比较。鉴于你问题中的信息,你真的不需要int32,你需要一个bool。

那么如果通过将比较结果移动到选择器中的1来重构pSelector成为选择器,该怎么办呢?

public static double GetIllnessRateByParity(IEnumerable<ILLNESS_OBJECT> pItems, int pParity, Func<ILLNESS_OBJECT, bool> pSelector)
{
    var filtered = pItems.Where(a => a.Parity == pParity);
    return Math.Round(filtered.Count(pSelector) / (double)GetBirthCountByParity(pItems, pParity), 2);
}
GetIllnessRateByParity(data, 1, a => a.AfterBirth==1)

答案 1 :(得分:0)

检查this

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var data = new List<ILLNESS_OBJECT>{
                new ILLNESS_OBJECT{ ID = 1, Parity = 1, Day = DateTime.Now, SomeString = "1", Long = 2L},
                new ILLNESS_OBJECT{ ID = 2, Parity = 2, Day = DateTime.Now, SomeString = "1", Long = 2L},
                new ILLNESS_OBJECT{ ID = 3, Parity = 1, Day = DateTime.Now, SomeString = "2", Long = 1L},
                new ILLNESS_OBJECT{ ID = 4, Parity = 1, Day = DateTime.Now, SomeString = "3", Long = 3L},
        };
        Console.WriteLine(GetIllnessRateByParity(data, 1, x => x.ID));
        Console.WriteLine(GetIllnessRateByParity(data, 1, x => int.Parse(x.SomeString)));
        Console.WriteLine(GetIllnessRateByParity(data, 1, x => (DateTime.Now - x.Day).Days + 1));
        Console.WriteLine(GetIllnessRateByParity(data, 1, x => (int)x.Long));
    }

    public static IConvertible GetIllnessRateByParity(IEnumerable<ILLNESS_OBJECT> pItems, int pParity, Func<ILLNESS_OBJECT, int> pSelector)
    {
        var filtered = pItems.Where(a => a.Parity == pParity);
        return Math.Round(filtered.Count(a => pSelector(a) == 1)/(double)1, 2);
    }

}

public class ILLNESS_OBJECT
{
    public int ID { get; set; }
    public DateTime Day { get; set; }
    public int Parity { get; set; }
    public int Afterbirth { get; set; }
    public string SomeString { get; set; }
    public long Long { get; set; }
}