You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用Expression Tree递归加密类/接口的String及嵌套属性?

问题描述

我已经掌握Expression Tree的基础知识,但在实现以下功能时遇到阻碍:需要修改类/接口实例,找出所有string属性并加密,同时递归处理所有“子”类/接口属性,包括IEnumerable<T>(其中T : class)。加密逻辑已经完成,但用Expression Tree实现对任意传入T的通用处理超出了当前理解范围。之前用反射实现过,但性能很快出现问题,以下是目前完成的代码:

使用AggregateHelper和PropertyHelper类,已实现基础的string加密:


测试类

public class SimpleEncryptionTest
{
   public string String1 { get; set; }
}

public class NestedClassEncryptionTest
{
   public string SomeString { get; set; }
   public SimpleEncryptionTest Inner { get; set; } 
}

public class ListClassEncryptionTest
{
    public List<string> StringList { get; set; }
}

单元测试

[TestMethod]
public void Encryption_works_on_a_simple_class()
{
    var testString = "this is only a test. If this had been a real emergency...";
    var sut = new SimpleEncryptionTest() { String1 = testString };
    sut.EncryptStringProperties();

    Assert.AreNotEqual(testString, sut.String1);
}

[TestMethod]
public void Round_trip_works_on_a_simple_class()
{
    var testString = "what string should I use?";
    var sut = new SimpleEncryptionTest() { String1 = testString };

    sut.EncryptStringProperties();
    sut.DecryptStringProperties();

    Assert.AreEqual(testString, sut.String1);
}

[TestMethod]
public void Round_trip_works_in_nested_class_scenario()
{
    var outerString = "what is your name?";
    var innerString = "Tony; what's your name?";

    var sut = new NestedClassEncryptionTest{
        SomeString = outerString,
        Inner = new SimpleEncryptionTest(){String1 = innerString }
    };

    sut.EncryptStringProperties();

    Assert.AreNotEqual(outerString, sut.SomeString);
    Assert.AreNotEqual(innerString, sut.Inner.String1);

    sut.DecryptStringProperties();

    Assert.AreEqual(outerString, sut.SomeString);
    Assert.AreEqual(innerString, sut.Inner.String1);
}

[TestMethod]
public void Round_trip_works_on_lists()
{
    var testone = "one";
    var testtwo = "two";
    var testStrings = new List<string>() { testone, testtwo };
    var sut = new ListClassEncryptionTest() { StringList = testStrings };

    sut.EncryptStringProperties();

    Assert.AreNotEqual(testone, sut.StringList[0]);
    Assert.AreNotEqual(testtwo, sut.StringList[1]);

    sut.DecryptStringProperties();

    Assert.AreEqual(testone, sut.StringList[0]);
    Assert.AreEqual(testtwo, sut.StringList[1]);
}

加密/解密扩展方法

/// <summary>
/// Iterates through an Object's properties and encrypts any strings it finds, 
/// recursively iterating any class or interface Properties.
/// </summary>
/// <typeparam name="T">Any type</typeparam>
/// <param name="genericObj">The object to encrypt</param>
/// <returns>The original object, with its string values encrypted.</returns>
public static T EncryptStringProperties<T>(this T obj)
    where T : class
{
    return Crypt(obj, EncryptStringAction);
}

/// <summary>
/// Iterates through an Object's properties and decrypts any strings it finds, 
/// recursively iterating any class or interface Properties.
/// </summary>
/// <typeparam name="T">Any type</typeparam>
/// <param name="genericObj">The object to decrypt</param>
/// <returns>The original object, with its string values decrypted.</returns>
public static T DecryptStringProperties<T>(this T obj)
{
    return Crypt(obj, DecryptStringAction);
}

private static T Crypt<T>(T obj, Action<PropertyHelper<T, string>, T> action)
{
    var stringProperties = new AggregateHelper<T, string>();
    foreach (var property in stringProperties.Properties)
    {
        var propertyHelper = stringProperties[property];
        action(propertyHelper, obj);
    }

    // how do I find the nested classes, interfaces and lists
    // using Expression Trees to feed them through the same processing?

    return obj;
}

private static void EncryptStringAction<T>(PropertyHelper<T, string> prop, T genericObj)
{
    var plainTextValue = (string)prop.GetValue(genericObj);
    prop.SetValue(genericObj, plainTextValue.ToEncryptedString());
}

private static void DecryptStringAction<T>(PropertyHelper<T, string> prop, T genericObj)
{
    var encryptedValue = (string)prop.GetValue(genericObj);
    prop.SetValue(genericObj, encryptedValue.ToDecryptedString());
}

目前代码可加密任意object的string属性,但无法递归处理嵌套对象、接口及集合,需要实现用Expression Tree找到嵌套类/接口属性并传入EncryptStringProperties方法,同时处理包含string的IEnumerable。


内容的提问来源于stack exchange,提问作者Scott Baker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:24:16