如何将自定义类对象传入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时,方法直接返回空列表,不符合常规逻辑——无筛选条件时应返回指定路径下的所有文件数据。
改进建议
恢复泛型并添加类型约束
给泛型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"));简化筛选委托
如果只针对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(); } }完善空筛选逻辑
无论filter是否为null,都应返回对应的数据(无筛选时返回全部),避免返回空列表导致业务逻辑出错。
内容的提问来源于stack exchange,提问作者Anton
相关产品推荐
相关产品推荐

