代码之家  ›  专栏  ›  技术社区  ›  bbsimonbb

字符串插值:如何使此函数适用于任何类型

  •  0
  • bbsimonbb  · 技术社区  · 6 年前

    这是一个在字符串插值中处理列表的函数。它接受一个List和一个内部Funcs,并为列表中的每个成员调用的内部Funcs的字符串结果附加一个分隔符。

    因此,以下内容构建了Insert语句的有效开头。。。

    static void Main(string[] args)
    {
        var tableName = "customers";
        var cols = new List<dynamic>
        {
            new { Name = "surname"},
            new { Name = "firstname"},
            new { Name = "dateOfBirth"}
        };
        Func<List<dynamic>, Func<dynamic, string>, string, string> ForEach = (list, func, separator) =>
            {
                var bldr = new StringBuilder();
                var first = true;
                foreach (var obj in list)
                {
                    if (!first)
                        bldr.Append(separator);
                    first = false;
                    bldr.Append(func(obj));
                }
                return bldr.ToString();
            };
    
        var InsertStatement = $"Insert into { tableName } ( {ForEach(cols, col => col.Name, ", ")} )";
        Console.WriteLine(InsertStatement);
        Console.ReadLine();
    }
    

    输出。。。

    Insert into customers ( surname, firstname, dateOfBirth )
    

    它适用于动态。我如何使它适用于任何类型?外部函数不应该关心列表中的类型,它只是将其传递给内部函数。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Francesc Castells    6 年前

    这个。NET框架已经为您提供了一个通用函数来实现您想要做的事情 String.Join 您可以将其与LINQ Select语句结合使用,这将允许您在泛型类型上使用lambda来选择要打印的属性。如果您感兴趣,可以查看这些方法的源代码,因为它们是开源的。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    public class MyType
    {
       public string Name { get; set; } 
    }
    
    public class Program
    {
        public static void Main()
        {
            var tableName = "customers";
            var cols = new List<MyType>
            {
                new MyType { Name = "surname"},
                new MyType { Name = "firstname"},
                new MyType { Name = "dateOfBirth"}
            };
    
            var InsertStatement = $"Insert into { tableName } ( {String.Join(", ", cols.Select(col => col.Name))} )";
            Console.WriteLine(InsertStatement);
        }
    }
    
        2
  •  0
  •   Alex Norcliffe    6 年前

    更换 dynamic 具有 object ,或 TValue 类型约束规定它必须是类( where TValue : class ),并致电 obj.ToString() 而不是仅仅 obj

    然而,这并不能保证它“适用于任何类型”——因为你需要知道这些类型都遵循一个契约,以输出所需的列名作为它们的字符串表示。为了获得更具体的信息,要求您接受的类型必须实现一些接口,例如 IColumnName 并将该接口放入类型约束中

        3
  •  0
  •   Reza Aghaei    6 年前

    您可以像这样轻松创建文本:

    var query = $"INSERT INTO {tableName}({string.Join(",", cols.Select(x=>x.Name))})";
    

    然而,如果 用于学习目的 您将使用泛型方法处理这种情况,您可以创建一个如下所示的泛型函数,然后轻松使用 for 使用环形和条形附加分离器 TrimEnd ,或者作为更好的选择,比如 String.Join implementation of .NET Framework 获取枚举器,如下所示:

    string Join<TItem>(
        IEnumerable<TItem> items, Func<TItem, string> itemTextSelecor, string separator)
    {
        var en = items.GetEnumerator();
        if (!en.MoveNext())
            return String.Empty;
        var builder = new StringBuilder();
        if (en.Current != null)
            builder.Append(itemTextSelecor(en.Current));
        while (en.MoveNext())
        {
            builder.Append(separator);
            if (en.Current != null)
                builder.Append(itemTextSelecor(en.Current));
        }
        return builder.ToString();
    }
    

    并以这种方式使用它:

    var tableName = "customers";
    var cols = new[]
    {
        new { Name = "surname"},
        new { Name = "firstname"},
        new { Name = "dateOfBirth"}
    };
    
    var InsertStatement = $"INSERT INTO {tableName} ({Join(cols, col => col.Name, ", ")})" 
        +  $"VALUES({Join(cols, col => $"@{col.Name}", ", ")})";