代码之家  ›  专栏  ›  技术社区  ›  Dathan

C/clr是否包含将属性的返回值标记为只读/不可变的机制?

  •  1
  • Dathan  · 技术社区  · 15 年前

    我环顾四周,到目前为止还没有找到一个好的方法来做到这一点。我敢肯定,这是一个常见的问题。

    假设我有以下几点:

    class SomeClass : IComparable
    { 
        private int myVal; 
        public int MyVal
        { 
            get { return myVal; } 
            set { myVal = value; }
        }
    
        public int CompareTo(object other) { /* implementation here */ }
    }
    
    class SortedCollection<T>
    {
        private T[] data;
        public T Top { get { return data[0]; } }
    
        /* rest of implementation here */
    }
    

    我的想法是,我要实现一个二进制堆,而不是只支持insert()和deletemin()操作,我要支持对堆栈上最高(或最低,视情况而定)优先级值的“扫视”。从来没有像海森堡那样,整个“你不能不改变事物”的不确定性原理。垃圾!

    显然,问题在于,上面没有提供任何方法来阻止调用代码通过Top属性修改myval(假定为SortedCollection),这一操作极有可能将堆置于错误的顺序。是否有任何方法可以防止修改通过top属性应用到堆的内部元素?或者,我只是使用带有警告的代码:“只有在插入实例和出列实例之间不修改任何实例时才是稳定的。”

    5 回复  |  直到 15 年前
        1
  •  1
  •   Mike Dinescu    15 年前

    要回答您的问题: ,无法实现您想要的行为类型-只要t是引用类型(甚至可能是某些值类型)

    你不能做太多的事。只要提供getter,调用代码就可以根据所述数据的可访问性(即属性、字段和方法)修改数据的内部内容。

    class SomeClass : IComparable
    { 
        private int myVal; 
        public int MyVal
        { 
            get { return myVal; } 
            set { myVal = value; }
        }
    
        public int CompareTo(object other) { /* implementation here */ }
    }
    
    
    class SortedCollection<T>
    {
        private T[] data;
        public T Top { get { return data[0]; } }
    
        /* rest of implementation here */
    }
    
    //..
    // calling code
    SortedCollection<SomeClass> col;
    col.Top.MyVal = 500;  // you can't really prevent this
    

    注释 我的意思是你不能真正阻止它 对于你无法控制的类 . 在这个例子中,正如其他人所说,您可以将myval的set设为私有或省略它;但是由于sortedcolleciton是一个泛型类, 你不能对别人的结构做任何事

        2
  •  1
  •   Joel Coehoorn    15 年前

    您可以有一个只读属性(即只有getter的属性):

    private int myVal;
    public int MyVal { get { return myVal; } }
    

    但要小心:这可能并不总是如你所期望的那样有效。考虑:

    private List<int> myVals;
    public List<int> MyVals { get { return myVals; } }
    

    在这种情况下,不能更改类使用的列表,但仍然可以调用该列表 .Add() , .Remove() 等方法。

        3
  •  1
  •   Sam Harwell    15 年前

    您的属性不必具有相同的可访问性 get / set . 这包括你的任何回报 价值类型 (典型地 struct 只包含值类型)或 不可变的引用类型 .

    public int MyVal
    { 
        get { return myVal; } 
        private set { myVal = value; }
    }
    

    对于可变引用类型,您有其他选项,例如返回 Clone() S或使用 ReadOnlyCollection<T> 要防止呼叫者更改它们:

    private List<int> data;
    
    public IList<int> Data
    {
        get { return new ReadOnlyCollection<int>(this.data); }
    }
    
        4
  •  0
  •   Mircea Grelus    15 年前

    只实现属性的getter,并通过使用添加/删除方法修改集合

        5
  •  0
  •   Tamás Szelei    15 年前

    我现在明白你的问题了。我认为这应该有效:

    class SortedCollection<T> where T: ICloneable
    {
        private T[] data;
        public T Top 
        { 
             get 
             { 
                 T ret = (T)data[0].Clone();
                 return ret; 
             }
        }
    
        /* rest of implementation here */
    }
    

    ICloneable约束确保类型参数实现ICloneable接口。(如果可以接受)