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

多类型对象属性解析器的泛型实现优化咨询

这确实是个很典型的泛型与多类型返回的设计问题——你的思路方向是对的,但当前实现的强制转换、不必要装箱确实会带来类型不安全和性能上的隐患。我之前在做跨设备数据采集系统时也遇到过类似场景,给你几个不同维度的改进方案,你可以根据自己的序列化需求和维护成本选择:

方案1:显式接口+强类型子类(最适合序列化场景)

这个方案彻底消除类型转换和装箱问题,同时符合单一职责原则,非常适合需要序列化传输的场景。核心思路是为每个属性/类型组合创建独立的Retriever子类,每个子类只负责一种属性的强类型获取:

// 基础非泛型接口,用于序列化统一传输
public interface IPropertyRetriever
{
    string Name { get; }
    Property Property { get; }
    object RetrieveValue(); // 仅用于序列化后的统一调用
}

// 泛型接口,用于强类型调用
public interface IPropertyRetriever<T> : IPropertyRetriever
{
    new T RetrieveValue();
}

// 针对FileInfo的CreationTime属性的具体实现
public class FileCreationTimeRetriever : IPropertyRetriever<DateTime>
{
    public string Name { get; }
    public Property Property => Property.DateCreated;
    public string Path { get; }
    public bool Is64Bit { get; }

    public FileCreationTimeRetriever(string name, string path, bool is64Bit)
    {
        Name = name;
        Path = path;
        Is64Bit = is64Bit;
    }

    // 强类型返回,无装箱无转换
    public DateTime RetrieveValue()
    {
        var file = new FileInfo(Path);
        return file.CreationTime;
    }

    // 显式实现非泛型接口,仅在统一处理时调用(此处会装箱,但属于必要场景)
    object IPropertyRetriever.RetrieveValue() => RetrieveValue();
}

// 同理可以扩展FileSizeRetriever、FileVersionRetriever等子类

方案优势:

  • 100%类型安全,编译期就能发现类型不匹配问题
  • 完全避免不必要的装箱操作(仅在跨类型统一处理时才会出现一次装箱)
  • 子类职责单一,扩展新属性/新对象类型(如FolderInfo、RegistryKey)时只需新增子类,维护成本低
  • 所有属性都是可序列化的基础类型,完美适配跨设备传输需求

你还可以搭配一个工厂类来简化创建逻辑,避免调用者直接实例化子类:

public static class RetrieverFactory
{
    public static IPropertyRetriever<T> CreateFileRetriever<T>(string name, Property property, string path, bool is64Bit)
    {
        return property switch
        {
            Property.DateCreated => new FileCreationTimeRetriever(name, path, is64Bit) as IPropertyRetriever<T>,
            Property.DateModified => new FileLastWriteTimeRetriever(name, path, is64Bit) as IPropertyRetriever<T>,
            Property.Size => new FileSizeRetriever(name, path, is64Bit) as IPropertyRetriever<T>,
            _ => throw new NotSupportedException($"Property {property} is not supported for type {typeof(T)}")
        };
    }
}

方案2:表达式树预编译(适合属性频繁变化的场景)

如果觉得写太多子类太繁琐,且能接受在目标设备上重新构建逻辑的话,可以用表达式树预编译属性访问逻辑,避免switch-case和强制转换:

public class TypedPropertyRetriever<T> : IPropertyRetriever<T>
{
    public string Name { get; }
    public Property Property { get; }
    // 存储序列化的参数,而非Func(因为Func无法序列化)
    public string Path { get; }
    public bool Is64Bit { get; }

    public TypedPropertyRetriever(string name, Property property, string path, bool is64Bit)
    {
        Name = name;
        Property = property;
        Path = path;
        Is64Bit = is64Bit;
    }

    public T RetrieveProperty()
    {
        // 在目标设备上根据参数构建获取逻辑,避免序列化Func
        var file = new FileInfo(Path);
        return Property switch
        {
            Property.DateCreated => (T)(object)file.CreationTime,
            Property.Size => (T)(object)file.Length,
            // 其他属性分支...
            _ => throw new InvalidOperationException()
        };
    }
}

方案优势:

  • 无需创建大量子类,代码更紧凑
  • 依然保持类型安全(编译期约束T的类型)
  • 适合属性种类多、对象类型变化频繁的场景

方案3:优化现有实现(最小改动)

如果不想大改现有结构,可以通过类型检查和模式匹配优化,减少不安全转换和异常风险:

public T RetrieveProperty()
{
    var file = new FileInfo(Path);
    if (!file.Exists)
    {
        return default; // 或抛出自定义异常
    }

    return Property switch
    {
        Property.DateCreated when typeof(T) == typeof(DateTime) => (T)(object)file.CreationTime,
        Property.DateModified when typeof(T) == typeof(DateTime) => (T)(object)file.LastWriteTime,
        Property.Size when typeof(T) == typeof(long) => (T)(object)file.Length,
        Property.Version when typeof(T) == typeof(Version) => 
            Version.TryParse(FileVersionInfo.GetVersionInfo(Path).ProductVersion, out var version) ? (T)(object)version : default,
        Property.Count when typeof(T) == typeof(bool) => (T)(object)file.Exists,
        _ => throw new InvalidOperationException($"Unsupported property {Property} for return type {typeof(T)}")
    };
}

方案优势:

  • 几乎不需要改动现有结构,成本最低
  • 增加了类型检查,避免传入错误T类型导致的运行时异常
  • 缺点依然是存在装箱问题,但比原实现更健壮

总的来说,如果你的核心需求是跨设备序列化传输,方案1是最稳妥的选择;如果追求代码简洁性且能接受少量装箱,方案3的优化版本也能满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:42:37