仅在属性中使用的私有范围的变量

本文关键字:范围 变量 属性 | 更新日期: 2023-09-27 18:23:40

是否可以在类中有一个实例变量,但只能由特定属性访问?

我经常创建"自我创建"属性,比如。。。

private IWGSLocation _location;
public IWGSLocation Location
{
    get
    {
        _location = _location ?? new WGSLocation();
        _location.Latitude = Latitude.GetValueOrDefault(0);
        _location.Longitude = Longitude.GetValueOrDefault(0);
        return _location;
    }
}

这意味着我不会每次访问该属性时都重新创建新的WGSLocation(或我需要的任何其他类型的对象,创建起来可能很昂贵,或者可能只需要创建一次)。缺点是我的类可以访问_location变量。但我真的不希望它这样做,所以如果有任何方法可以让一个实例变量只能在属性本身中使用呢?

我正沿着这些思路思考。。。

public IWGSLocation Location
{
    get
    {
        WGSLocation _location = _location ?? new WGSLocation();
        _location.Latitude = Latitude.GetValueOrDefault(0);
        _location.Longitude = Longitude.GetValueOrDefault(0);
        return _location;
    }
}

仅在属性中使用的私有范围的变量

我同意拥有持久本地是一个很好的语言功能,也就是说,生存期基于实例的生存期,但作用域(按名称访问变量是合法的程序文本区域)是本地的变量。像一些语言一样,拥有"静态"本地语言也会很好

遗憾的是,这不是C#的一个功能,我们也没有添加它的计划。拥有它很好,但拥有它还不足以证明费用的合理性,也不足以推迟或取消"拥有更好"的功能。

它只是"很好拥有",因为如果你有一个私有字段,它已经是类的私有实现细节了。如果您不希望它在属性之外使用,那么就不要编写在属性外部使用它的代码。如果你的一个同事试图这样做,在代码审查中对他们进行严厉打击。

我想我可以补充一点:在编写改变状态的属性getter时要非常小心默认情况下,属性getter是在调试器中查看对象时评估的,如果调试某个对象并让调试器更改字段值,这可能会让非常困惑,因为正在检查对象

类可以访问它并不一定是一个缺点。它仍然在逻辑上封装在同一个实体中。

您在之后的内容不可能按照您希望的方式。类的所有区域都可以看到成员变量,并且局部变量被限制在其定义的范围内。

相反,您可以将位置封装在一个容器类中。此类是您的成员变量。返回IWGSLocation时,只需钻取容器类:

public class LocationContainer
{
    public IWGSLocation InnerLocation { get; private set; }
    public void SetLocation(WGSLocation loc)
    {
        InnerLocation = loc;
    }
}
private readonly LocationContainer _container = new LocationContainer();
public IWGSLocation Location
{
    get
    {
        if (_container.InnerLocation == null)
        {
            _container.SetLocation(...);
        } 
        return _container.InnerLocation;
    }
}

这不会阻止类接触_container,但会让其他开发人员三思而后行,如果不显式调用SetLocation,他们将无法意外地更改位置。

您甚至可以在容器的SetLocation中放置一次保护设置。

更新:我实际上会在这里使用懒惰类,类似于:

private readonly Lazy<IWGSLocation> _location = new Lazy<IWGSLocation>(()
 =>
{
    var l = new WGSLocation();
    l.Latitude = Latitude.GetValueOrDefault(0);
    l.Longitude = Longitude.GetValueOrDefault(0);
    return l;
});
public IWGSLocation Location
{
    get { return _location.Value; }
}

请注意,这是头编的:-)

在我看来,您当前的实现已经崩溃。

var x=obj.Location;
x.Latitude = 1;
Console.WriteLine(x.Latitude);//1
var y=obj.Location;
Console.WriteLine(x.Latitude);//WTF it changed

我建议将IWGSLocation设置为不可变的,或者只在创建时对其进行修改,这取决于您想要的语义。