【问题标题】:Generics and Functions in C#C# 中的泛型和函数
【发布时间】:2010-12-24 12:39:15
【问题描述】:

这是一些代码,它不会编译,但本质上我想要创建一个函数,它解析为 CSV 文件,然后将 CSV 列表中的值转换为特定类型。

    Func<string, Func<string,T>, IEnumerable<T>> parser =(string csv, Func<string, T> newFunc) =>
    {
        List<T> items = new List<T>();
        string[] ary = csv.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string val in ary)
        {
            try
            {
                items.Add(newFunc(val));
            }
            catch { }
        }
        return items;
    }

我希望这个函数是通用的,所以 T 是我希望将 CSV 列表转换为的类型。这个函数的用法是这样的:

 string csvList ="1,2,3";
        IEnumerable<int> list = parser(csvList, (string val) => { return Convert.ToInt32(val)});

但是这显然行不通,因为我还没有定义 T。所以是否可以以类似于这样的泛型方法的方式定义 T:

    Func<T><string, Func<string,T>, IEnumerable<T>> parser =(string csv, Func<string, T> newFunc) =>
    {
        List<T> items = new List<T>();
        string[] ary = csv.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string val in ary)
        {
            try
            {
                items.Add(newFunc(val));
            }
            catch { }
        }
        return items;
    }

然后像这样使用它:

string csvList ="1,2,3";
        IEnumerable<int> list = parser<int>(csvList, (string val) => { return Convert.ToInt32(val)});

有没有办法在 C# 中做这样的事情?

-- 进一步编辑

感谢您的回复,在我编写的代码中,我实际上使用了您所描述的方法,但是我想知道是否可以在不需要方法的情况下将其作为 Func 执行称呼。

【问题讨论】:

  • 这个函数式编程怎么样?因为你在写一个 C# 函数?
  • 旁注:如果您要重新发明 CSV 解析器,请记住正确处理引用的值(尤其是包含逗号的值)。

标签: c# .net generics functional-programming function


【解决方案1】:

试试这个。我认为这可以完成您想要做的事情,而无需大量花招。

string csvList = "1,2,3";
IEnumerable<int> list = parser<int>(csvList, Convert.ToInt32);



static IEnumerable<T> parser<T>(string csv, Converter<string, T> converter)
{
    string[] array = csv.Split(new string[] { "," }, 
                        StringSplitOptions.RemoveEmptyEntries);

    T[] items = Array.ConvertAll(array, converter);

    return items;
}

更新: 如果你想要一行,你可以这样做:

string csvList = "1,2,3";
var list = csvList.Split(new string[] { "," }, 
           StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x));

【讨论】:

  • 我实际上在我的代码中使用了一个方法,但我想知道是否可以不使用并使用 Func。
【解决方案2】:

parser 的函数签名在语法上不正确,应定义如下。

Func<string, Func<string,T>, IEnumerable<T>>
    parser<T>(string csv, Func<string, T> newFunc)
{
    // implementation
}

注意,定义泛型函数时,需要在函数名之后,参数列表之前指定泛型参数(参见上面的parser&lt;T&gt;)。

【讨论】:

    【解决方案3】:

    根据用法,我会说您需要一个返回 IEnumerable&lt;&gt; 的函数,而不是 Func&lt;&gt;

    这会将整个事情简化为:

        IEnumerable<T> parser<T>(string csv, Func<string, T> newFunc)
        {
            List<T> items = new List<T>();
    
            string[] ary = csv.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string val in ary)
            {
                try
                {
                    items.Add(newFunc(val));
                }
                catch
                {
                    // empty catch alert
                }
            }
            return items;
        }
    

    您的用例缺少分号(在ToInt32() 之后):

        string csvList ="1,2,3";
        IEnumerable<int> list = 
          parser<int>(csvList, (val) => { return Convert.ToInt32(val); });
    

    编辑,感谢 BFree:如果您不需要在解析器内部进行异常处理(并且我希望空捕获仅在示例代码中存在),您可以消除 List&lt;T&gt; items 并改用 yield return .

    【讨论】:

      【解决方案4】:

      也许我遗漏了一些东西,但我认为这是你需要的:

      public IEnumerable<T> Parse<T>(string csv, Func<string, T> func)
      {
         foreach(var item in csv.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries))
         {
            yield return func(item);
         }
      }
      

      【讨论】:

      • 是的,items 也可以删除,我错过了。不过我会借的。
      猜你喜欢
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 2017-06-02
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-01
      相关资源
      最近更新 更多