我想有一个类“A”与(例如)排序列表集“SrtdLst”属性,并且这类中“A”允许的“SrtdLst”项加或减。但在“A”级的情况下,只允许获取或设置项目的内容,而不是增加新的项目或减去现有的。在代码:

class A
{
    public SortedList<string, string> SrtdLst = new SortedList<string, string>();

    public A()
    {
        // This must work:
        SrtdLst.Add("KeyA", "ValueA");
        // This too:
        SrtdLst["KeyA"] = "ValueAAA";
    }
}

class B
{
    public A a = new A();
    public B()
    {
        // I want the following code to fail:
        a.SrtdLst.Add("KeyB", "ValueB");
        // But this must work:
        a.SrtdLst["KeyA"] = "ValueBBB";
   }
}

更新:我想创建一个像System.Data.SqlClient.SqlCommand类。对于存储过程可以使用填充“参数”的集合的成员“DeriveParameters”,所以仅在每个项目的值可以被修改。

如何才能做到这一点?

有帮助吗?

解决方案

如果你想在编译时禁止修改操作,你需要一个类型安全的解决方案。

声明一个接口,用于允许公开的操作。使用该接口作为属性类型。

public interface IReadOnlyList<T>
{
    T this[int index] { get; }

    int Count { get; }
}

然后声明实现该接口,并从标准收集类继承的类。

public class SafeList<T> : List<T>, IReadOnlyList<T> { }

假设你的接口定义吧,你将不再需要执行手动什么,作为基类已经提供了实现。

这派生类作为存储属性值的字段的类型使用。

public class A
{
    private SafeList<string> _list = new SafeList<string>();

    public IReadOnlyList<string>
    {
        get { return _list; }
    }
}

在A类,可以直接使用_list,所以修改内容。类A的客户将只能通过IReadOnlyList<T>使用可用的操作的子集。

有关你的榜样,你正在使用排序列表而不是列表,所以接口可能需要在

public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
    V this[K index] { get; }        
}

我将它继承了IEnumerable为好,这是只读的,无论如何,所以是绝对安全的。然后,安全的类将是:

public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }

但除此之外,它是同样的想法。

更新:只注意到(由于某种原因,我无法捉摸)你不想禁止修改操作 - 你只是想禁止一些修改操作。很奇怪,但它仍然是相同的解决方案。任何你想要的操作,让“开起来”的界面:

public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
    V this[K index] { get; set; }        
}

当然,这是错误的名称为接口现在...到底为什么要禁止通过添加加,但通过索引不禁止呢? (分度器可用于添加的物品,正如添加方法也可以。)

<强>更新

从您的评论,我认为你的意思是你要允许分配到现有的键/值对的值,但不允许分配给一个先前未知的关键。显然,作为键被串在运行时指定的,有没有办法赶上,在编译时。所以,你不妨去运行时检查:

public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
    IDictionary<TKey, TValue> _realDictionary;

    public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
    {
        _realDictionary = realDictionary;
    }

    public TValue this[TKey key]
    {
        get { return _realDictionary[key]; }

        set 
        {
            if (!_realDictionary.Contains(key))
                throw new InvalidOperationException();

            _realDictionary[key] = value;
        }
    }

    // Implement Add so it always throws InvalidOperationException

    // implement all other dictionary methods to forward onto _realDictionary
}

您有任何时间一个普通的字典,并且希望把它交给一些你不信任更新现有的值,把它包在其中的一个方法。

其他提示

编辑:原来的答复如下。正如埃里克指出,我没有注意到你的的要求它是只读的 - 只是为了防止Add操作。那听起来不像是个好主意,我作为Add和索引制定者之间的唯一区别是,如果元素已经存在Add抛出异常。这可以很容易地由呼叫者无论如何伪造了。

为什么要限制只是一个操作?


<强>原始应答

首先,不使用公共字段。这是碰到问题正确的方式。

它看起来像你想有一个只读的包装类圆形任意IDictionary。然后,您可以返回包装一个公共属性,而从你的类中访问私有变量。例如:

class A
{
    private SortedList<string, string> sortedList = new SortedList<string, string>();

    public IDictionary<string, string> SortedList 
    {
        get { return new ReadOnlyDictionaryWrapper(sortedList);
    }

    public A()
    {
        sortedList.Add("KeyA", "ValueA");
        sortedList["KeyA"] = "ValueAAA";
    }
}

现在你刚刚找到一个ReadOnlyDictionary实现......我无法实现它的权利,但我会回来,如果有必要...

就榜上无名私人,并将其作为一个索引:

class A {

   private SortedList<string, string> _list;

   public A() {
      _list = new SortedList<string, string>()
   }

   public string this[string key] {
      get {
         return _list[key];
      }
      set {
         _list[key] = value;
      }
   }

}

现在您只能使用索引来访问的项目:

a["KeyA"] = "ValueBBB";

但是,作为列表的索引允许新项目的创建,你将不得不在索引中添加代码,以防止,如果你不希望这样做是不可能的。

如果该键被称为外部类,那么你可以添加一个ChangeItem(键,NEWVALUE)和ReadItem(键),在包装类。然后保持SortedList的私有类。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top