Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何通过Linq表达式序列化对象_C#_Linq_Nhibernate_Json.net_Expression - Fatal编程技术网

C# 如何通过Linq表达式序列化对象

C# 如何通过Linq表达式序列化对象,c#,linq,nhibernate,json.net,expression,C#,Linq,Nhibernate,Json.net,Expression,我想用linq表达式序列化一个对象。让我们假设,我有以下课程: public class User { public string Username { get; set; } public string Password { get; set; } public IList<Usergroup> Usergroups { get; set; } } public class Usergroup { public string Name { ge

我想用linq表达式序列化一个对象。让我们假设,我有以下课程:

public class User
{
    public string Username { get; set; }

    public string Password { get; set; }

    public IList<Usergroup> Usergroups { get; set; }
}

public class Usergroup
{
    public string Name { get; set; }

    public List<User> Users { get; set; }

    public List<AccessRight> AccessRights { get; set; }

    public Screen Screen { get; set; }
}

public class AccessRight
{
    public int AccessLevel { get; set; }
}

public class Screen
{
    public string Name { get; set; }
}
公共类用户
{
公共字符串用户名{get;set;}
公共字符串密码{get;set;}
公共IList用户组{get;set;}
}
公共类用户组
{
公共字符串名称{get;set;}
公共列表用户{get;set;}
公共列表访问权限{get;set;}
公共屏幕屏幕{get;set;}
}
公共类访问权
{
公共int访问级别{get;set;}
}
公共类屏幕
{
公共字符串名称{get;set;}
}
现在我有了一个对象用户,我想用它的用户组对它进行序列化,对于所有用户组,它的访问权限和屏幕,但不包括其他用户的列表

是否有一种方法(或可用的Git/NuGet项目)可以使用linq表达式实现这一点。 比如:

var string=Serialize(user,u=>u.Usergroups,u=>u.Usergroups.Select(ug=>ug.AccessRights),…)
当我搜索json.net和表达式时,我只找到了如何序列化表达式本身的解决方案

我想使用该解决方案初始化和取消固定NHibernate实体

提前谢谢你试过NuGet吗

假设我有以下数据:

var user = new User()
{
   Username = "User 1",
   Password = "***",
   Usergroups = new List<Usergroup>()
   {
      new Usergroup()
      {
        Name = "Administrator",
        Screen = new Screen() { Name = "Users" },
        AccessRights = new List<AccessRight>()
        {
            new AccessRight() { AccessLevel = 9999 }
        },
        Users = new List<User>()
        {
            new User()
            {
                Password = "@#$%",
                Usergroups = new List<Usergroup>(),
                Username = "User 2"
            }
        }
    }
   }
};

//Here you serialize your object.
var json = JsonConvert.SerializeObject(user);
预期结果

{
  "Username": "User 1",
  "Password": "***",
  "Usergroups": [{
     "Name": "Administrator",
     "AccessRights": [
        {
          "AccessLevel": 9999
        }
      ],
     "Screen": {
       "Name": "Users"
      }
     }]
 }
你试过NuGet吗

假设我有以下数据:

var user = new User()
{
   Username = "User 1",
   Password = "***",
   Usergroups = new List<Usergroup>()
   {
      new Usergroup()
      {
        Name = "Administrator",
        Screen = new Screen() { Name = "Users" },
        AccessRights = new List<AccessRight>()
        {
            new AccessRight() { AccessLevel = 9999 }
        },
        Users = new List<User>()
        {
            new User()
            {
                Password = "@#$%",
                Usergroups = new List<Usergroup>(),
                Username = "User 2"
            }
        }
    }
   }
};

//Here you serialize your object.
var json = JsonConvert.SerializeObject(user);
预期结果

{
  "Username": "User 1",
  "Password": "***",
  "Usergroups": [{
     "Name": "Administrator",
     "AccessRights": [
        {
          "AccessLevel": 9999
        }
      ],
     "Screen": {
       "Name": "Users"
      }
     }]
 }

这里最简单的方法是使用匿名类型,在序列化时,我们只需要定义一个与预期类型类似的结构,它不必是支持反序列化的精确克隆。
我们可以很容易地省略构造的匿名类型中的属性,然后将其序列化

我说这种方法“简单”,因为它不涉及对模型定义或DTO声明的修改。这是一个非侵入性的解决方案,可以应用于序列化场景中的所有模型,在这些场景中,您不需要或不希望序列化完整的对象图

现在让我们把nhibernate从图片中去掉,如果您有一个
User
类的实例想要序列化,您可以简单地使用它

var simpleCereal = Newtonsoft.Json.JsonConvert.SerializeObject(new { user.Username, user.Password, UserGroups = user.Usergroups.Select(ug => new { ug.AccessRights, ug.Name, ug.Screen }).ToList() });
即使我们使用了匿名类型,如果指定忽略JsonSerializerSettings中缺少的成员,序列化结果仍将反序列化回有效的
User
对象
newJSONSerializerSettings{MissingMemberHandling=MissingMemberHandling.Ignore})

我们可以通过接受lambda的简单helper方法实现您建议的语法:

/// <summary>
/// Serialize an object through a lambda expression that defines the expected output structure
/// </summary>
/// <typeparam name="T">Type of the object to serialize</typeparam>
/// <param name="target">The target object to serialize</param>
/// <param name="expr">The lambda expression that defines the final structure of the serialized object</param>
/// <returns>Serialized lambda representation of the target object</returns>
public static string Serialize<T>(T target, System.Linq.Expressions.Expression<Func<T, object>> expr)
{
    var truncatedObject = expr.Compile().Invoke(target);
    return Newtonsoft.Json.JsonConvert.SerializeObject(truncatedObject);
}
下面是我用来测试这个的代码,省略了OPs类定义,你可以在问题中找到它们

static void Main(string[] args)
{
    User user = new User
    {
        Username = "Test User",
        Password = "Password",
        Usergroups = new List<Usergroup>
        {
            new Usergroup
            {
                Name = "Group12", AccessRights = new List<AccessRight>
                {
                    new AccessRight { AccessLevel = 1 },
                    new AccessRight { AccessLevel = 2 }
                },
                Screen = new Screen { Name = "Home" },
                Users = new List<User>
                {
                    new User { Username = "Other1" },
                    new User { Username = "Other2" }
                }
            },
            new Usergroup
            {
                Name = "Group3Only", AccessRights = new List<AccessRight>
                {
                    new AccessRight { AccessLevel = 3 },
                },
                Screen = new Screen { Name = "Maintenance" },
                Users = new List<User>
                {
                    new User { Username = "Other1" },
                    new User { Username = "Other2" }
                }
            }
        }
    };
    // Standard deep serialization, will include the deep User objects within the user groups.
    var standardCereal = Newtonsoft.Json.JsonConvert.SerializeObject(user);
    // Simple anonymous type serialize, exclude Users from within UserGroups objects
    var simpleCereal = Newtonsoft.Json.JsonConvert.SerializeObject(new { user.Username, user.Password, UserGroups = user.Usergroups.Select(ug => new { ug.AccessRights, ug.Name, ug.Screen }).ToList() });
    // Same as above but uses a helper method that accepts a lambda expression
    var lambdaCereal = Serialize(user, u => new { u.Username, u.Password, UserGroups = u.Usergroups.Select(ug => new { ug.AccessRights, ug.Name, ug.Screen }).ToList() });
    // NOTE: simple and lambda serialization results will be identical. 
    // deserialise back into a User
    var userObj = Newtonsoft.Json.JsonConvert.DeserializeObject<User>(
        lambdaCereal, 
        new Newtonsoft.Json.JsonSerializerSettings
        {
            MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore
        });
}

/// <summary>
/// Serialize an object through a lambda expression that defines the expected output structure
/// </summary>
/// <typeparam name="T">Type of the object to serialize</typeparam>
/// <param name="target">The target object to serialize</param>
/// <param name="expr">The lambda expression that defines the final structure of the serialized object</param>
/// <returns>Serialized lambda representation of the target object</returns>
public static string Serialize<T>(T target, System.Linq.Expressions.Expression<Func<T, object>> expr)
{
    var truncatedObject = expr.Compile().Invoke(target);
    return Newtonsoft.Json.JsonConvert.SerializeObject(truncatedObject);
}
您提到您正在使用nhibernate,如果对象尚未在内存中具体化,那么如果您没有在
UserGroups
扩展上扩展
Users
属性(因此不急于加载
Users
属性),那么它将不会包含在序列化输出中


这里最简单的方法是使用匿名类型,在序列化时,我们只需要定义一个与预期类型类似的结构,它不必是支持反序列化的精确克隆。
我们可以很容易地省略构造的匿名类型中的属性,然后将其序列化

我说这种方法“简单”,因为它不涉及对模型定义或DTO声明的修改。这是一个非侵入性的解决方案,可以应用于序列化场景中的所有模型,在这些场景中,您不需要或不希望序列化完整的对象图

现在让我们把nhibernate从图片中去掉,如果您有一个
User
类的实例想要序列化,您可以简单地使用它

var simpleCereal = Newtonsoft.Json.JsonConvert.SerializeObject(new { user.Username, user.Password, UserGroups = user.Usergroups.Select(ug => new { ug.AccessRights, ug.Name, ug.Screen }).ToList() });
即使我们使用了匿名类型,如果指定忽略JsonSerializerSettings中缺少的成员,序列化结果仍将反序列化回有效的
User
对象
newJSONSerializerSettings{MissingMemberHandling=MissingMemberHandling.Ignore})

我们可以通过接受lambda的简单helper方法实现您建议的语法:

/// <summary>
/// Serialize an object through a lambda expression that defines the expected output structure
/// </summary>
/// <typeparam name="T">Type of the object to serialize</typeparam>
/// <param name="target">The target object to serialize</param>
/// <param name="expr">The lambda expression that defines the final structure of the serialized object</param>
/// <returns>Serialized lambda representation of the target object</returns>
public static string Serialize<T>(T target, System.Linq.Expressions.Expression<Func<T, object>> expr)
{
    var truncatedObject = expr.Compile().Invoke(target);
    return Newtonsoft.Json.JsonConvert.SerializeObject(truncatedObject);
}
下面是我用来测试这个的代码,省略了OPs类定义,你可以在问题中找到它们

static void Main(string[] args)
{
    User user = new User
    {
        Username = "Test User",
        Password = "Password",
        Usergroups = new List<Usergroup>
        {
            new Usergroup
            {
                Name = "Group12", AccessRights = new List<AccessRight>
                {
                    new AccessRight { AccessLevel = 1 },
                    new AccessRight { AccessLevel = 2 }
                },
                Screen = new Screen { Name = "Home" },
                Users = new List<User>
                {
                    new User { Username = "Other1" },
                    new User { Username = "Other2" }
                }
            },
            new Usergroup
            {
                Name = "Group3Only", AccessRights = new List<AccessRight>
                {
                    new AccessRight { AccessLevel = 3 },
                },
                Screen = new Screen { Name = "Maintenance" },
                Users = new List<User>
                {
                    new User { Username = "Other1" },
                    new User { Username = "Other2" }
                }
            }
        }
    };
    // Standard deep serialization, will include the deep User objects within the user groups.
    var standardCereal = Newtonsoft.Json.JsonConvert.SerializeObject(user);
    // Simple anonymous type serialize, exclude Users from within UserGroups objects
    var simpleCereal = Newtonsoft.Json.JsonConvert.SerializeObject(new { user.Username, user.Password, UserGroups = user.Usergroups.Select(ug => new { ug.AccessRights, ug.Name, ug.Screen }).ToList() });
    // Same as above but uses a helper method that accepts a lambda expression
    var lambdaCereal = Serialize(user, u => new { u.Username, u.Password, UserGroups = u.Usergroups.Select(ug => new { ug.AccessRights, ug.Name, ug.Screen }).ToList() });
    // NOTE: simple and lambda serialization results will be identical. 
    // deserialise back into a User
    var userObj = Newtonsoft.Json.JsonConvert.DeserializeObject<User>(
        lambdaCereal, 
        new Newtonsoft.Json.JsonSerializerSettings
        {
            MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore
        });
}

/// <summary>
/// Serialize an object through a lambda expression that defines the expected output structure
/// </summary>
/// <typeparam name="T">Type of the object to serialize</typeparam>
/// <param name="target">The target object to serialize</param>
/// <param name="expr">The lambda expression that defines the final structure of the serialized object</param>
/// <returns>Serialized lambda representation of the target object</returns>
public static string Serialize<T>(T target, System.Linq.Expressions.Expression<Func<T, object>> expr)
{
    var truncatedObject = expr.Compile().Invoke(target);
    return Newtonsoft.Json.JsonConvert.SerializeObject(truncatedObject);
}
您提到您正在使用nhibernate,如果对象尚未在内存中具体化,那么如果您没有在
UserGroups
扩展上扩展
Users
属性(因此不急于加载
Users
属性),那么它将不会包含在序列化输出中


谢谢你的回答。我已经使用了Newtonsoft.Json,我还知道JsonIgnore属性。但是我想在不同的上下文中序列化用户。当我在登录的上下文中读取用户时,我需要用户及其用户组和用户组的属性(如AccessRights等)。但是当我在UserManagement的上下文中读取用户时,我只需要没有AccessRights的UserGroups。当我在UserGroupManagement的上下文中读取UserGroup时,我还需要用户。这就是我尝试动态序列化它的原因。你读过关于条件属性序列化的内容吗?那将是我的替代解决方案。实际上,我刚刚编写了一个JsonIgnoreWithContextAttribute,所以我可以决定是否忽略属性。但是这个解决方案感觉。。。嗯。。。复古。也许您还可以使用DTO来公开每个场景所需的属性,而不是将其序列化。我已经仔细考虑了很久,是否应该使用DTO,或者是否应该将实体直接传递到各个层。我还在评估阶段。实体和DTO中的重复代码阻止我使用DTO。然后我需要多个UsergroupDto。Ohe是LoginUsergroupDto,一个是UserManagementUserGroup