C#Linq替代lodash省略功能

时间:2016-10-14 10:53:55

标签: c# linq lodash

示例输入:

// remove sensitive data    
var user = db.Users.Where(x => x.Id == '123').ToList()
      .Omit("PasswordHash", "PasswordSalt", "SecretDataAsInteger");

输出:

{
  FirstName: "...",
  LastName: "...",
  PasswordHash: "", // default value instead of real value
  PasswordSalt: "",
  SeretDataAsInteger: 0
}

类似于: https://lodash.com/docs/4.16.4#omit

设定:

  • 我更喜欢解决方案而不选择新对象并设置除我想省略的属性之外的每个属性,即

var user = ..Users.Select(x => new User {/* here I set each property */})

因为这会导致更新所有引用,以防我稍后更新了User模型属性

  • 在omit函数中传递对象而不是将属性名称作为字符串传递

3 个答案:

答案 0 :(得分:1)

下面是我为您创建的一个类,应该使用提供的属性名称列表将它们设置为Property类型的默认值。使用您的示例:

// remove sensitive data    
var user = db.Users.Where(x => x.Id == '123').ToList()
  .OmitProperties("PasswordHash", "PasswordSalt", "SecretDataAsInteger");

请记住加入System.Reflection

public static class EnumerableExtensions {
        public static IEnumerable<T> OmitProperties<T>(this IEnumerable<T> enumerable, params string[] propertyNames) {
            PropertyInfo[] propertiesToOmit = typeof(T).GetProperties()
                .Where(p => propertyNames.Contains(p.Name))
                .ToArray();

            foreach (var item in enumerable) {
                foreach (var property in propertiesToOmit) {
                    property.SetValue(item, null);
                }

                yield return item;
            }
        }
    }

答案 1 :(得分:1)

如果您可以控制User类,则可以添加User的构造函数。使此构造函数复制所有字段。您可以使用反射来轻松地这样做。如果通过动态生成执行所需工作的辅助方法来实现此功能,则只需生成一次辅助方法。给定此构造函数,您可以编写

var user = db.Users.Where(x => x.Id == 123).AsEnumerable()
  .Select(x => new User(x) {
    PasswordHash = "",
    PasswordSalt = "",
    SecretDataAsInteger = 0
  }).ToList();

这使其保持类型安全:您不会意外省略User没有的属性(例如,您尝试省略PasswordSlat而不是PasswordSalt),并且您不能通过将属性设置为属性类型不支持的值(例如,通过将其设置为SecretDataAsInteger来尝试省略null)来意外省略属性,并且无论如何都会尝试这样做由编译器标记而不是在运行时爆炸。

答案 2 :(得分:1)

这是一个不是Linq并实际更新基础对象的选项。可能不是你想要的,但它完成了这项工作:

public static IEnumerable<T> ApplyToAll<T>(this IEnumerable<T> sequence, 
    params Action<T>[] action)
{
    foreach (var element in sequence)
    {
        foreach (var action in actions)
        {
            omission(action);
        }
        yield return element;
    }
}

而不是传递属性的字符串名称,而是传递一些作用于输入的操作:

var redactedUsers = users.ApplyToAll(
    u => u.Password = "",
    u => u.Name = "Hello " + u.Name);