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

如何将自定义类对象传入Predicate委托?附代码优化咨询

问题描述

我正在编写一个数据处理类,其GetData方法依赖传入的Predicate委托实现数据筛选。由于该方法需要供其他类调用,因此使用了泛型,但无法将自定义类对象传入委托参数。我尝试过将泛型传入委托,也试过直接在函数中使用自定义类,但都没有解决问题。之后我根据建议修改了代码,想咨询下该优化后代码是否存在问题。

初始代码

public class Program
{
    public static void Main()
    {
        var result1 = new MyDataProcessing().GetData<MyFile>("C:\\", MyFunc);
        var result2 = new MyDataProcessing().GetData<MyFile>("C:\\", MyFunc2);
    }  
    static bool MyFunc(MyFile file) => file.FileInfo.Name.Contains("A");
    static bool MyFunc2(MyFile file) => file.FileInfo.Length > 1000;
}
interface MyData
{
}
public class MyFile : MyData
{
    public MyFile(string name)
    {
        FileInfo = new FileInfo(name);
    }
   public FileInfo FileInfo { get; }
}

public class MyDataProcessing 
{
    public List<T> GetData<T>(string path, Predicate<T>? filter = null)
    {
        List<T> list = new();
        IEnumerable<string> files;
        if (filter != null && typeof(T).Name is MyFile)
        {
            files = Directory.EnumerateFiles(path).Where(x => filter(new MyFile(x)));
            foreach (var file in files)
                list.Add(new MyFile(file));
        }
        return list;
    }
}

优化后代码

public class Program
{
    public bool MyFunc(IMyData data)
    {
        if (data is MyFile myfile)
        {
            return myfile.FileInfo.Name.Contains("A");
        }

        return false;
    }
    public bool MyFunc2(IMyData data)
    {
        if (data is MyFile myfile)
        {
            return myfile.FileInfo.Length > 1000;
        }

        return false;
    }

    public static void Main()
    {
        var p = new Program();
        var result1 = new MyDataProcessing().GetData("C:\\", p.MyFunc);
        var result2 = new MyDataProcessing().GetData("C:\\", p.MyFunc2);
    }


    public interface IMyData { }

    public class MyFile : IMyData
    {
        public MyFile(string name)
        {
            FileInfo = new FileInfo(name);
        }
        public FileInfo FileInfo { get; }
    }

    public class MyDataProcessing
    {
        public List<IMyData> GetData(string path, Predicate<IMyData>? filter = null)
        {
            List<IMyData> list = new();
            IEnumerable<string> files;

            if (filter != null)
            {
                files = Directory.EnumerateFiles(path).Where(x => filter(new MyFile(x)));
                foreach (var file in files)
                    list.Add(new MyFile(file));
            }
            return list;
        }
    }

优化后代码存在的问题

  • 类型安全性不足:返回的List<IMyData>需要调用方强制转换为MyFile才能访问FileInfo属性,容易引发InvalidCastException,且失去了编译时的类型检查。
  • 筛选逻辑冗余:每个Predicate方法都要先判断data is MyFile,后续如果扩展其他实现IMyData的类,这种重复判断会增加维护成本。
  • 泛型优势浪费:原代码试图用泛型实现通用数据处理,但优化后直接绑定到IMyData,无法针对特定类型提供强类型的返回结果,灵活性降低。
  • 对象重复创建:在Where筛选时创建了一次MyFile对象,添加到列表时又重新创建一次,造成不必要的内存开销和性能损耗。
  • 空筛选处理不合理:当filter为null时,方法直接返回空列表,不符合常规逻辑——无筛选条件时应返回指定路径下的所有文件数据。

改进建议

  1. 恢复泛型并添加类型约束
    给泛型T添加IMyData约束,同时通过工厂模式解决实例化问题,避免反射的复杂性:

    public interface IDataFactory<T> where T : IMyData
    {
        T Create(string filePath);
    }
    
    public class MyFileFactory : IDataFactory<MyFile>
    {
        public MyFile Create(string filePath) => new MyFile(filePath);
    }
    
    public class MyDataProcessing
    {
        public List<T> GetData<T>(string path, IDataFactory<T> factory, Predicate<T>? filter = null) where T : IMyData
        {
            var fileItems = Directory.EnumerateFiles(path).Select(factory.Create);
            if (filter != null)
            {
                fileItems = fileItems.Where(item => filter(item));
            }
            return fileItems.ToList();
        }
    }
    

    调用示例:

    var result1 = new MyDataProcessing().GetData("C:\\", new MyFileFactory(), file => file.FileInfo.Name.Contains("A"));
    
  2. 简化筛选委托
    如果只针对MyFile类型处理,可以直接使用强类型的Predicate<MyFile>,避免类型判断:

    public class MyDataProcessing
    {
        public List<MyFile> GetData(string path, Predicate<MyFile>? filter = null)
        {
            var files = Directory.EnumerateFiles(path).Select(p => new MyFile(p));
            return filter != null ? files.Where(f => filter(f)).ToList() : files.ToList();
        }
    }
    
  3. 完善空筛选逻辑
    无论filter是否为null,都应返回对应的数据(无筛选时返回全部),避免返回空列表导致业务逻辑出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 06:23:11