C# 通过lambda factory vs direct创建对象;新类型();语法 例如,考虑实用类 SerialZistabelist: public class SerializableList : List<ISerializable> { public T Add<T>(T item) where T : ISerializable { base.Add(item); return item; } public T Add<T>(Func<T> factory) where T : ISerializable { var item = factory(); base.Add(item); return item; } }
我也可以通过保理使用它,比如:C# 通过lambda factory vs direct创建对象;新类型();语法 例如,考虑实用类 SerialZistabelist: public class SerializableList : List<ISerializable> { public T Add<T>(T item) where T : ISerializable { base.Add(item); return item; } public T Add<T>(Func<T> factory) where T : ISerializable { var item = factory(); base.Add(item); return item; } },c#,lambda,factory-pattern,C#,Lambda,Factory Pattern,我也可以通过保理使用它,比如: var serializableList = new SerializableList(); var item1 = serializableList.Add(new Class1()); var item2 = serializableList.Add(new Class2()); var serializableList = new SerializableList(); var item1 = serializableList.Add(() =>
var serializableList = new SerializableList();
var item1 = serializableList.Add(new Class1());
var item2 = serializableList.Add(new Class2());
var serializableList = new SerializableList();
var item1 = serializableList.Add(() => new Class1());
var item2 = serializableList.Add(() => new Class2());
第二种方法似乎是首选的使用模式,正如我最近注意到的那样。是真的吗(如果是的话,为什么会这样),还是仅仅是口味的问题?举个例子,工厂法很愚蠢。除非被调用方需要能够控制实例化点、实例化多个实例或延迟计算,否则这只是无用的开销 编译器将无法优化外委托创建 参考您在问题注释中给出的使用工厂语法的示例。这两个示例都试图(尽管效果很差)提供有保证的实例清理
如果考虑使用语句:
using (var x = new Something()) { }
天真的实现方式是:
var x = new Something();
try
{
}
finally
{
if ((x != null) && (x is IDisposable))
((IDisposable)x).Dispose();
}
此代码的问题在于,在分配x
之后,但在进入try
块之前,可能会发生异常。如果发生这种情况,x
将无法正确处理,因为finally
块将不会执行。为了解决这个问题,使用语句的代码实际上更像:
Something x = null;
try
{
x = new Something();
}
finally
{
if ((x != null) && (x is IDisposable))
((IDisposable)x).Dispose();
}
使用factory参数引用的两个示例都试图处理相同的问题。传递工厂允许在受保护的块中实例化实例。直接传递实例允许在过程中出现错误,并且不会调用Dispose()
在这些情况下,传递工厂参数是有意义的。缓存
在您提供的示例中,它没有其他人指出的意义。我再举一个例子
public class MyClass{
public MyClass(string file){
// load a huge file
// do lots of computing...
// then store results...
}
}
private ConcurrentDictionary<string,MyClass> Cache = new ....
public MyClass GetCachedItem(string key){
return Cache.GetOrAdd(key, k => new MyClass(key));
}
公共类MyClass{
公共MyClass(字符串文件){
//加载一个巨大的文件
//做大量的计算。。。
//然后存储结果。。。
}
}
私有ConcurrentDictionary缓存=新建。。。。
公共MyClass GetCachedItem(字符串键){
返回Cache.GetOrAdd(key,k=>newmyclass(key));
}
在上面的例子中,假设我们正在加载一个大文件,我们正在计算一些东西,我们对计算的最终结果感兴趣。为了加快访问速度,当我尝试通过缓存加载文件时,缓存将返回缓存条目(如果有),只有当缓存未找到该项时,它才会调用工厂方法,并创建MyClass的新实例
所以您要多次读取文件,但只创建一个只保存一次数据的类实例。此模式仅用于缓存目的
但若您并没有缓存,并且每次迭代都需要调用新的操作符,那个么使用工厂模式就毫无意义了
备用错误对象或错误日志记录
出于某种原因,如果创建失败,List可以创建一个错误对象,例如
T defaultObject = ....
public T Add<T>(Func<T> factory) where T : ISerializable
{
T item;
try{
item = factory();
}catch(ex){
Log(ex);
item = defaultObject;
}
base.Add(item);
return item;
}
T defaultObject=。。。。
公共T添加(函数工厂),其中T:ISerializable
{
T项;
试一试{
项目=工厂();
}捕获(ex){
对数(ex);
item=defaultObject;
}
基础。添加(项目);
退货项目;
}
在本例中,您可以监视factory在创建新对象时是否生成异常,当发生异常时,您可以记录错误,并返回其他内容,并在列表中保留一些默认值。我不知道这会有什么实际用途,但错误日志记录在这里听起来更合适。不,没有通过工厂而不是值的一般偏好。但是,在非常特殊的情况下,将希望传递工厂方法而不是值
想想看:
将参数作为值传递与
将其作为工厂方法传递(例如使用Func
)?
答案很简单:执行顺序
- 在第一种情况下,需要传递值,因此必须在调用目标方法之前获取该值
- 在第二种情况下,您可以将价值创建/计算/获取推迟到目标方法需要时
您为什么要推迟价值创造/计算/获取?我想到了显而易见的事情:
- 处理器密集型或内存密集型的价值创建,您只希望在真正需要价值时(按需)创建价值。这是懒惰加载
- 如果值的创建依赖于目标方法可以访问但不能从外部访问的参数。因此,您将传递
Func
,而不是Func
这个问题比较了不同目的的方法。第二个应命名为CreateAndAdd(Func工厂)
因此,根据所需的功能,应该使用一种或另一种方法。第二种方法使用lambda表达式语法,我认为这两种方法之间没有任何区别。我看不出调用传递到列表的意义。@DoanCuong,我知道会弹出单词lambda
,所以我更新了标题来支持它:)“第二种方法似乎是首选的使用模式…”在哪里?这似乎毫无意义,效率低下。在其他示例中是否有我遗漏的用例?@NPSF3000,我可以尝试找到更多。我的理解可能是,因为第二种方法在消费方法(Add
)的上下文中创建了一个对象,所以它留下了一个选项来处理该方法内部的任何异常。尽管这些代码片段中并不是这样。另外,我相信C#编译器足够聪明,可以优化这样的代码,所以这两种方法都同样有效,至少对于我的简单示例来说是如此。我同意这一点,尽管我觉得我可能仍然没有做到这一点