使派生类中的只读属性可写

alw*_*ing 6 c#

我想要实现的目标如下:我在BaseClass中声明了一个属性.如果通过基类'指针访问此属性,则只有getter可用,但如果使用派生类指针,我希望能够获取并设置该属性.所以intellisense甚至不应该显示基本指针的setter.

public class BaseClass
{
     public virtual int MyProperty
     {
         get { return 1; }
         set {;}//This would show the setter in Intellisense
     }
}   

public class DerivedClass : BaseClass
{
     int intValue;

     public override int MyProperty
     {
         set { intValue = value;}
     }
}   
Run Code Online (Sandbox Code Playgroud)

一个现实的例子:
考虑一种情况,你有一个从Person类派生的Parent和Child类.想象一下属性-RestrictionLevel,两者都可以读取它,但只有父级可以设置值.有没有更好的方法来设计这种情况?

Fre*_*örk 9

我能想到的唯一方法是用新的方式遮蔽房产:

public class DerivedClass : BaseClass
{
    int intValue;

    public new int MyProperty
    {
        get { return intValue; }
        set { intValue = value; }
    }
}  
Run Code Online (Sandbox Code Playgroud)

注意如何声明属性new而不是override.这意味着,当然,这MyProperty类型的DerivedClass有无关MyProperty的类型BaseClass,它是恰好具有相同的名称(从而隐藏从基类中的一个),一个全新的属性.

结果是这样的:

DerivedClass d = new DerivedClass();
d.MyProperty = 42;

BaseClass b = new DerivedClass();
b.MyProperty = 42;    /* compilation error: Property or indexer 
                                            'TheNamespace.BaseClass.MyProperty' 
                                            cannot be assigned to -- it is 
                                            read only */
Run Code Online (Sandbox Code Playgroud)

另外,正如@silky在评论中所述:

(虽然我建议你做,而父母,请参考相同的变量,以避免一个非常令人困惑的情况)但我真的不认为这是适当的.

...您可能希望新属性访问基类中的属性(通过base.MyProperty受保护的setter完成).例如,请考虑以下事项:

DerivedClass d = new DerivedClass();
d.MyProperty = 42;

BaseClass b = d;
Console.WriteLine(b.MyProperty);  // prints 1
Run Code Online (Sandbox Code Playgroud)

也就是说,使用时我总觉得有点脏new(当我想到它时,我不确定我是否真的在生产代码中完成了).

更新
既然你给(我在某种程度上理解,一个示例场景Parent是可以设置RestrictionLevelChild),它可以解决这样的:

public enum RestrictionLevel
{
    Low,
    Medium,
    Grounded
}

public class Person
{
    public RestrictionLevel RestrictionLevel { get; private set; }
    protected static void SetRestrictionLevelInternal(Person person, RestrictionLevel restrictionLevel)
    {
        person.RestrictionLevel = restrictionLevel;
    }
}

public class Child : Person { }

public class Parent : Person
{
    public void SetRestrictionLevel(Child child, RestrictionLevel restrictionLevel)
    {
        SetRestrictionLevelInternal(child, restrictionLevel);
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着以下代码有效:

Child c = new Child();
Parent p = new Parent();
p.SetRestrictionLevel(c, RestrictionLevel.Grounded);
Run Code Online (Sandbox Code Playgroud)

......但这个不是:

Child c = new Child();
c.SetRestrictionLevel(c, RestrictionLevel.Low);
Run Code Online (Sandbox Code Playgroud)

该方法SetRestrictionLevelInternal可以从被称为任何后代类型(包括Child),但不能从调用外部类型本身.因此,您无法SetRestrictionLevelInternalParent实例上调用.在上面的示例中,我们选择公开一个public方法,该方法又调用该protected方法.


zih*_*tki 5

编程到接口,而不是实现:

public interface IFoo
{
    int MyProp { get; }
}

public interface IFooWithSetter
{
    int MyProp { get; set; }
}

public class FooImplementation : IFoo, IFooWithSetter
{
    public int MyProp
    {
        get { return 100; }
        set { }
    }
}  
Run Code Online (Sandbox Code Playgroud)

使用范例:

IFoo var1 = new FooImplementation(); // only getter is available in var1
IFooWithSetter var2 = (IFooWithSetter) var1; // setter and getter is available in var2  
Run Code Online (Sandbox Code Playgroud)

您可以轻松地为具有不同合同的接口使用一些私有修饰符.这个解决方案很简单,IMO套件适合您的任务.
如果你认为做一些你想隐藏/限制的行动很容易,那你就是对的.而同样是用任何可能的方式.


Noo*_*ilk -1

这是不可能的(据我所知)。无论如何,这都会令人困惑。您想要这样做有什么特别的原因吗?