C# 在这种情况下,使用.Net惰性类是一种过度使用吗?
我最近在.Net中了解到了懒惰类,可能已经过度使用它了。下面我举了一个例子,在这个例子中,事情本来可以以一种急切的方式进行评估,但如果反复调用,就会导致重复相同的计算。在这个特定的示例中,使用Lazy的成本可能无法证明它的好处,我对此也不确定,因为我还不知道lambda和Lazy调用有多么昂贵。我喜欢使用链式惰性属性,因为我可以将复杂的逻辑分解为小的、可管理的块。我也不再需要考虑初始化东西的最佳位置在哪里——我需要知道的是,如果我不使用它们,东西将不会被初始化,并且在我开始使用它们之前会被初始化一次。然而,一旦我开始使用lazy和lambdas,一个简单的类现在变得更复杂了。我无法客观地判断什么时候这是合理的,什么时候这在复杂性、可读性、可能的速度方面是过度的。你的一般建议是什么C# 在这种情况下,使用.Net惰性类是一种过度使用吗?,c#,lazy-evaluation,lambda,lazy-initialization,C#,Lazy Evaluation,Lambda,Lazy Initialization,我最近在.Net中了解到了懒惰类,可能已经过度使用它了。下面我举了一个例子,在这个例子中,事情本来可以以一种急切的方式进行评估,但如果反复调用,就会导致重复相同的计算。在这个特定的示例中,使用Lazy的成本可能无法证明它的好处,我对此也不确定,因为我还不知道lambda和Lazy调用有多么昂贵。我喜欢使用链式惰性属性,因为我可以将复杂的逻辑分解为小的、可管理的块。我也不再需要考虑初始化东西的最佳位置在哪里——我需要知道的是,如果我不使用它们,东西将不会被初始化,并且在我开始使用它们之前会被初始化
// This is set once during initialization.
// The other 3 properties are derived from this one.
// Ends in .dat
public string DatFileName
{
get;
private set;
}
private Lazy<string> DatFileBase
{
get
{
// Removes .dat
return new Lazy<string>(() => Path.GetFileNameWithoutExtension(this.DatFileName));
}
}
public Lazy<string> MicrosoftFormatName
{
get
{
return new Lazy<string>(() => this.DatFileBase + "_m.fmt");
}
}
public Lazy<string> OracleFormatName
{
get
{
return new Lazy<string>(() => this.DatFileBase + "_o.fmt");
}
}
//这在初始化期间设置一次。
//其他3个属性是从这个属性派生出来的。
//以.dat结尾
公共字符串文件名
{
得到;
私人设置;
}
私有文件库
{
得到
{
//删除.dat
返回新的Lazy(()=>Path.GetFileNameWithoutExtension(this.DatFileName));
}
}
公共名称
{
得到
{
返回新的Lazy(()=>this.DatFileBase+“\m.fmt”);
}
}
公共名称
{
得到
{
返回新的Lazy(()=>this.DatFileBase+“_o.fmt”);
}
}
您说过“我不再需要考虑在哪里初始化东西是最好的”
这是一个不好的习惯。你应该确切地知道你的计划中发生了什么 当需要传递一个对象,但需要进行一些计算时,您应该懒惰。 因此,只有当它被使用时,它才会被计算出来 除此之外,您还需要记住,使用lazy检索的对象不是被请求时处于程序状态的对象。
只有在使用对象时,才能获得对象本身。如果您获得了对程序状态很重要的对象,那么以后就很难对其进行调试。这可能有点过头了 当泛型类型的创建或计算成本很高时,和/或在依赖类的每次使用中并不总是需要泛型类型时,通常应该使用Lazy 更可能的是,在这里调用getter的任何东西都需要在调用getter时立即使用实际的字符串值。在这种情况下,返回一个Lazy实例是不必要的,因为调用代码只需立即计算Lazy实例,就可以得到它真正需要的东西。懒惰的“及时”本性在这里被浪费了,因此,雅格尼(你不需要它)
也就是说,懒惰固有的“开销”并没有那么大。懒虫只不过是一个引用lambda的类,它将生成泛型类型。lambda的定义和执行成本相对较低;它们只是方法,在编译时由CLR提供mashup名称。额外类的实例化是主要的关键,即使这样也不可怕。然而,从编码和性能的角度来看,这都是不必要的开销。使用
惰性
来创建简单的字符串属性确实是一种过度使用。使用lambda参数初始化Lazy
的实例可能比执行单个字符串操作要昂贵得多。还有一个其他人还没有提到的更重要的参数-请记住,lambda参数由编译器解析为相当复杂的结构,比字符串串联复杂得多。另一个适合使用延迟加载的领域是可以在部分状态下使用的类型。作为一个例子,考虑如下:
public class Artist
{
public string Name { get; set; }
public Lazy<Manager> Manager { get; internal set; }
}
公共类艺术家
{
公共字符串名称{get;set;}
公共惰性管理器{get;内部集合;}
}
在上面的示例中,消费者可能只需要使用我们的Name属性,但必须填充可能使用或可能不使用的字段可能是延迟加载的地方。我说不应该,因为在某些情况下,提前加载可能更有效。。。。取决于应用程序需要执行的操作。这似乎不是为了节省昂贵对象的创建/加载而使用的
惰性
,而是(可能无意中)包装一些任意委托以延迟执行。您可能希望/打算让派生属性getter返回的是字符串
,而不是惰性
对象
如果调用代码看起来像
string fileName = MicrosoftFormatName.Value;
var lazyName = MicrosoftFormatName; // Not yet evaluated
// some other stuff, maybe changing the value of DatFileName
string fileName2 = lazyName.Value;
那么,显然没有什么意义,因为您是立即“延迟加载”的
如果调用代码看起来像
string fileName = MicrosoftFormatName.Value;
var lazyName = MicrosoftFormatName; // Not yet evaluated
// some other stuff, maybe changing the value of DatFileName
string fileName2 = lazyName.Value;
然后您可以看到,创建lazyName
对象时,fileName2
可能无法确定
在我看来,Lazy
不适合用于公共财产;在这里,getter将返回新的(如全新的、不同的、额外的)Lazy
对象,因此每个调用方(可能)将获得不同的.Value
!所有的Lazy
属性都取决于在第一次访问它们的值时设置的DatFileName
,因此您将始终需要考虑相对于每个派生属性的使用何时初始化
请参阅MSDN文章“”,它创建了一个私有惰性支持变量和一个公共属性getter,如下所示:
get { return _privateLazyObject.Value; }
使用Lazy,我可能猜您的代码应该/可能喜欢什么<