从静态方法访问隐藏的属性

时间:2018-11-01 13:11:47

标签: c#

给出以下内容

class BaseClass
{
    public int Property {get; protected set;}
}

class DerivedClass : BaseClass
{
    public new int Property {get; set;} //Hides BaseClass.Property

    public static DerivedClass Build()
    {
         var result = new DerivedClass
         {
              Property = 17;
              //base.Property = 17; // this doesn't compile
         }
         //((BaseClass)result).Property = 17; // this doesn't compile
    }
}

有什么方法可以通过DerivedClass内部的静态方法设置BaseClass.Property。

反射或不安全代码不是我想要的!我想要一种简单的方法来设置我们合法有权访问的内容,但是我无法解决设置方法。

5 个答案:

答案 0 :(得分:3)

  

有什么方法可以通过DerivedClass内部的静态方法设置BaseClass.Property。

是的,请重新考虑您的设计。这是有缺陷的。隐藏一个属性,然后想在基类和派生类上设置完全相同的值?似乎确实有问题。

您不一定需要隐藏该属性,可以覆盖它,但是这样做没有太大意义。似乎唯一的目标是在基类和派生类上具有不同的访问修饰符。这违反了OOP规则,应该避免。

答案 1 :(得分:2)

如果可以引入另一个 intermediate 类,那么显然可以做到这一点。但是正如其他人所说的,它不仅具有代码 smell ,而且具有一定的毒性。

class BaseClass
{
    public int Property { get; protected set; }
}

class InterClass : BaseClass
{
    protected void DoFunnyStuff(int value)
    {
        this.Property = value;
    }
}

class DerivedClass : InterClass
{
    public new int Property { get; set; } //Hides BaseClass.Property

    public static DerivedClass Build()
    {
        DerivedClass result = new DerivedClass
        {
            Property = 17
            //base.Property = 17; // this doesn't compile
        };
        result.DoFunnyStuff(17);
        return result;
        //((BaseClass)result).Property = 17; // this doesn't compile
    }
}

因此DerivedClass确实仍从BaseClass继承,但不是直接继承。您可以运用各种技巧来尽量减少InterClass的存在下暴露出多少其他代码。

答案 2 :(得分:1)

您似乎希望以一种不再可变的方式修改API行为。那么,为什么不定义一个新属性,它实际上是不可变的,而是改用现有的Obsolete来隐藏原始属性而不隐藏呢?

class LegacyClass
{
    [Obsolete("Use NewMember instead")]
    public string ExistingMember { get; set; } // should actually be immutable
    public string NewMember { get { ... } }
}

这样,您就不会破坏现有的代码。

答案 3 :(得分:1)

以下是从类的静态方法访问重写的属性的方法:

  1. 向该类添加访问基本属性的新属性:

    private double BaseProperty { get => base.MyProperty; set => base.MyProperty = value; }
    
  2. 使用您的静态文件中的新属性:

    var result = new DerivedClass
    {
        BaseProperty = 17;
    }
    

在这种情况下,上述技术是我发现的最干净的解决方案。
考虑在类库中引用BindableProperty的XAML。
(就我而言,类库是Xamarin Forms。)

在不更改属性名称的情况下,我想将基本属性(由编译到库中的代码使用)与XAML可见属性(在我的子类中)分离。
具体用途是使文本自动适应,这是X-Forms尚不支持的。

这里相关的细节是,我具有以下BindableProperty声明:

public new static readonly BindableProperty FontSizeProperty =
    BindableProperty.Create("FontSize", typeof(double), typeof(AutofitLabel), -1.0,
        propertyChanged: (BindableObject bindable, object oldValue, object newValue) => {
            ((AutofitLabel)bindable).BaseFontSize = (double)newValue;
        });

使用此私有属性:

private double BaseFontSize { get => base.FontSize; set => base.FontSize = value; }

这完成的工作是首先将base.FontSize设置为XAML中设置的值,该值将由库Label或其他包含文本的视图中的布局逻辑使用。在子类的其他地方,一旦知道可用的宽度/高度,我就会根据需要降低base.FontSize的逻辑。

这种方法可以在不更改其源代码的情况下使用该库,但对于我的子类的客户端来说,它似乎是内置的自动调整功能。
更改客户端代码可见的FontSize(代表请求的大小)无效。 However, that is the approach taken by Charles Petzold in XF Book Ch. 5 "EmpiricalFontSizePage"。另外,Petzold的页面本身具有自动调整大小的功能-这并不方便。

面临的挑战是需要告诉图书馆要使用的实际FontSize。 解决这个问题。

我在网上找到的所有其他方法都需要复杂的自定义渲染器,复制XF库中已经存在的逻辑。

答案 4 :(得分:0)

是的,可以通过反思:Property hiding and reflection (C#)

否,这是不可能的,如果您通过设计隐藏属性,那是因为您不想从DerivedClass授予对该属性的访问权限

Reflection允许您出于特定目的进行访问,这不是使用反射的简单方法。

这是一种访问您已被设计隐藏的属性的黑客方式。

如果您想以合法方式访问财产,则不应将其隐藏。