【问题标题】:Privately scoped variable only for use within property私有范围的变量仅用于属性内
【发布时间】:2012-02-08 11:29:21
【问题描述】:

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

我经常像这样创建“自我创造”的属性......

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

这意味着每次我访问财产。缺点是我的班级可以访问 _location 变量。但我真的不想要它,所以如果有任何方法可以拥有一个只能在属性本身内使用的实例变量?

我正在考虑这些方面的一些事情......

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

【问题讨论】:

  • 当我测量到急切创建它是我的应用程序的瓶颈时,我更喜欢使用惰性初始化属性。

标签: c# properties


【解决方案1】:

我同意拥有 persistent locals 将是一个不错的语言特性——也就是说,lifetimes 的变量基于实例的生命周期,但其 scopes(通过名称访问变量是合法的程序文本区域)是本地的。最好有“静态”本地人,就像某些语言一样。

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

这只是“很高兴拥有”,因为当然,如果您有一个私有字段,它已经是该类的私有实现细节。如果您不希望它在属性之外使用,那么不要编写在属性之外使用它的代码。如果您的一位同事试图这样做,请在代码审查中对他们进行打击。

我想我可以补充一下:在编写改变状态的属性 getter 时要非常小心。默认情况下,属性 getter 是在调试器中查看对象时评估的,它可能非常令人困惑 正在调试某些东西并让调试器 仅仅因为您正在检查一个对象而更改字段的值。

【讨论】:

  • 关于调试器的优点。这些天我很少使用调试器,所以我忘记了那个问题。
  • “如果您的一位同事试图这样做,请在代码审查中对他们进行打击。”我喜欢它!
  • 抱歉,我敢打赌,大多数代码从来没有看到过代码审查,而且我个人从不喜欢打我的同事。似乎总是回到我身边。很想知道你对我的回答有何看法。
【解决方案2】:

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

你所追求的不可能以你想要的方式。成员变量对类的所有区域都是可见的,并且局部变量被限制在它们定义的范围内。

您可以做的是将位置包装在容器类中。这个类是你的成员变量。返回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; }
}

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

【讨论】:

  • +1 是一个不错的解决方案。但还是有点啰嗦!如果语言中有一种方法可以做到这一点,我会更喜欢它:) 当然,除非我所做的在某些方面根本上是错误的。
  • @AntonyScott 是的,这有点罗嗦,但如果你试图保护一个类的元素不受同一个类中的其他元素的影响,我会说你应该回顾一下,看看你是否真的需要两个班。我想你的要求是错误的,但我不理会这些讨论。
  • @AntonyScott 其实就是用惰性类就行了。
【解决方案3】:

在我看来,您当前的实现已损坏。

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

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

【讨论】:

  • 啊,是的。你是对的。我将其更改为使用空合并运算符。我曾经只在尚未设置对象的情况下创建对象。好地方:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
相关资源
最近更新 更多