C# 在这种情况下,使用.Net惰性类是一种过度使用吗?

C# 在这种情况下,使用.Net惰性类是一种过度使用吗?,c#,lazy-evaluation,lambda,lazy-initialization,C#,Lazy Evaluation,Lambda,Lazy Initialization,我最近在.Net中了解到了懒惰类,可能已经过度使用它了。下面我举了一个例子,在这个例子中,事情本来可以以一种急切的方式进行评估,但如果反复调用,就会导致重复相同的计算。在这个特定的示例中,使用Lazy的成本可能无法证明它的好处,我对此也不确定,因为我还不知道lambda和Lazy调用有多么昂贵。我喜欢使用链式惰性属性,因为我可以将复杂的逻辑分解为小的、可管理的块。我也不再需要考虑初始化东西的最佳位置在哪里——我需要知道的是,如果我不使用它们,东西将不会被初始化,并且在我开始使用它们之前会被初始化

我最近在.Net中了解到了懒惰类,可能已经过度使用它了。下面我举了一个例子,在这个例子中,事情本来可以以一种急切的方式进行评估,但如果反复调用,就会导致重复相同的计算。在这个特定的示例中,使用Lazy的成本可能无法证明它的好处,我对此也不确定,因为我还不知道lambda和Lazy调用有多么昂贵。我喜欢使用链式惰性属性,因为我可以将复杂的逻辑分解为小的、可管理的块。我也不再需要考虑初始化东西的最佳位置在哪里——我需要知道的是,如果我不使用它们,东西将不会被初始化,并且在我开始使用它们之前会被初始化一次。然而,一旦我开始使用lazy和lambdas,一个简单的类现在变得更复杂了。我无法客观地判断什么时候这是合理的,什么时候这在复杂性、可读性、可能的速度方面是过度的。你的一般建议是什么

    // 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,我可能猜您的代码应该/可能喜欢什么<