使用LINQ将对象列表转换为大写

5

我有如下代码。我想将列表中的所有项目转换为大写。

有没有在Linq中实现这个功能的方法?

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

public class MyClass
{
    List<Person> myList = new List<Person>{ 
        new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
        new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
    };
}

更新

我不想循环或逐个字段进行操作。是否有通过反射将每个属性的值转换为大写的方法?


你可以使用List.ForEach来实现,但这只是foreach循环的替代。Linq不是用于更改数据对象,而是用于查询。 - Amiram Korach
为什么不在对象创建时规范化名称? - user7116
@Kris-I:为什么你需要这样的通用方法?你有大量的对象,而且你不想为每个对象编写特殊的循环/方法来将字符串属性转换为大写吗? - sll
1
@Kris-I:你的更新没有任何意义。如果你有N个对象和M个属性,你将需要调用一个方法,它将循环至少MIN(N,M)次,进行M*N次方法调用。即使使用反射,你也会循环... - user7116
我们能否在这里澄清一下?听起来你想要一个通用的方法来为你完成这项工作,你希望它改变基础数据还是提供一个新项目? - Bob Vale
5个回答

19

为什么要使用LINQ?

使用List<T>.ForEach

myList.ForEach(z =>
                {
                    z.FirstName = z.FirstName.ToUpper();
                    z.LastName = z.LastName.ToUpper();
                });

编辑:不知道你为什么想要通过反射来做这个(我个人不会这样做...),但是这里有一些代码,将大写所有返回字符串的属性。请注意,它远非完美,但如果您真的想使用反射,它可以为您提供一个基础...
public class Person
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int Age { get; set; }
}

public static class MyHelper
{
    public static void UppercaseClassFields<T>(T theInstance)
    {
        if (theInstance == null)
        {
            throw new ArgumentNullException();
        }

        foreach (var property in theInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            var theValue = property.GetValue(theInstance, null);
            if (theValue is string)
            {
                property.SetValue(theInstance, ((string)theValue).ToUpper(), null);
            }
        }
    }

    public static void UppercaseClassFields<T>(IEnumerable<T> theInstance)
    {
        if (theInstance == null)
        {
            throw new ArgumentNullException();
        }

        foreach (var theItem in theInstance)
        {
            UppercaseClassFields(theItem);
        }
    }
}

public class Program
{
    private static void Main(string[] args)
    {
        List<Person> myList = new List<Person>{
            new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
            new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
        };

        MyHelper.UppercaseClassFields<Person>(myList);

        Console.ReadLine();
    }
}

1
@BobVale 是的,会的。如果一个属性没有setter,它会抛出异常。这只是一个想法,而不是一个可直接复制粘贴的解决方案 ;) - ken2k
1
还有为什么要使用双重泛型?你不能只声明签名为public static void UppercaseClassFields<T>(IEnumerable<T> theInstance)吗? - Bob Vale
1
@BobVale 完全同意使用双重泛型。正在编辑代码示例。 - ken2k
é‡č――UppercaseClassFields<T>(T theInstance)äđŸäžšåūˆæœ‰åļŪåŠĐ :) - sll
理想情况下,为了提高性能,您应该使用Linq.Expressions构建编译后的操作来更新数据。这意味着只需要使用一次反射...不知道这是否是问题中Linq的起源。 - Bob Vale
显示剩余2条评论

4

LINQ不提供更新基础数据的功能。使用LINQ,您可以从现有列表创建新列表:

// I would say this is overkill since creates a new object instances and 
// does ToList()
var updatedItems = myList.Select(p => new Person 
                              {
                                FirstName = p.FirstName.ToUpper(), 
                                LastName = p.LastName.ToUpper(), 
                                Age = p.Age
                              })
                         .ToList();

如果不是必须使用LINQ,我建议使用foreach循环。
更新:
为什么需要这样的解决方案?以通用方式实现只有一种方法 - 反射。

1
@davenewza 那不是一个 LINQ 方法。 - Jesse C. Slicer
好的,这是一个案例(不是LINQ的)。 - sll
@Jesse:没错,但这是sll提出的两个选项之外的另一个选择。 - Dave New
谢谢,但是没有任何属性需要用到属性或循环。请看我的更新1。 - TheBoubou
1
为什么在最后调用ToList()?这会立即执行查询!Linq之所以如此美妙,是因为它建立在“yield return”和“foreach”的基础上。几乎每个Linq方法都返回IEnumerable(IQuerable),这使您可以链接许多方法,并且查询不会被执行,直到您需要迭代该IEnumerable(IQuerable)或显式调用ToList()、ToArray()、AsEnumerable()等(在这种情况下,您将失去“yield return”的魔力)。 - Aleksei Chepovoi
1
有时您必须立即执行linq查询,以对数据集进行快照并返回给调用方,有时您需要使用ToList()来符合现有的API返回/输入数据类型。在这种情况下,它是为了符合原始问题中使用List<Person>的示例,过度使用ToList()是注释。 - sll

3
最简单的方法是使用ConvertAll
myList = myList.ConvertAll(d => d.ToUpper());

ForEach循环不太不同,原始列表被循环,而ConvertAll则创建一个新的列表,需要重新分配。
var people = new List<Person> { 
    new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
    new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
people = people.ConvertAll(m => new Person 
         {
             FirstName = m.FirstName?.ToUpper(), 
             LastName = m.LastName?.ToUpper(), 
             Age = m.Age
         });

回答您的更新:

我不想循环或逐个字段进行操作。通过反射有没有一种方法来大写每个属性的值?

如果您不想循环或逐个字段操作,可以使用类中的属性使其转换为大写,例如:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string FirstNameUpperCase => FirstName.ToUpper();
    public string LastNameUpperCase => LastName.ToUpper();
}

或者您可以像这样使用后向字段。
public class Person
{
    private string _firstName;
    public string FirstName {
        get => _firstName.ToUpper();
        set => _firstName = value;
    }

    private string _lastName;
    public string LastName {
        get => _lastName.ToUpper();
        set => _lastName = value;
    }

    public int Age { get; set; }
}

1

你只能使用linq来提供一个新对象列表

var upperList = myList.Select(p=> new Person {
   FirstName = (p.FirstName == null) ? null : p.FirstName.ToUpper(),
   LastName = (p.LastName == null) ? null : p.LastName.ToUpper(),
   Age = p.Age
   }).ToList();

谢谢,但不需要属性或循环。请查看我的更新1。 - TheBoubou

0
p.lastname.ToString().ToUpper().Contains(TextString)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接