C# 禁止访问公共列表';s方法

C# 禁止访问公共列表';s方法,c#,oop,C#,Oop,这是一个极其简化的问题描述。考虑到我有以下几点: interface IMyClass { IList<int> MyList { get; set; } void AddToList(int newVal); } public class MyClass: IMyClass { public IList<int> MyList { get; set; } public void AddToList(int newVal) {

这是一个极其简化的问题描述。考虑到我有以下几点:

interface IMyClass {
    IList<int> MyList { get; set; }
    void AddToList(int newVal);
}

public class MyClass: IMyClass {
    public IList<int> MyList { get; set; }
    public void AddToList(int newVal)
    {
        // custom implementation goes here
        MyList.Add(newVal);
    }
}
接口IMyClass{
IList MyList{get;set;}
无效地址列表(int newVal);
}
公共类MyClass:IMyClass{
公共IList MyList{get;set;}
公共无效地址列表(int newVal)
{
//这里是自定义实现
MyList.Add(newVal);
}
}
我得到了一个接口
IMyClass
,我无法更改。任务是实现此接口以及
addToList
方法

问题是,即使我实现了
addToList
方法,用户仍然有可能通过直接访问
MyList
属性来添加项目

有没有办法禁止用户直接在列表上使用
Add()
Remove()
Insert()


到目前为止,我已经尝试实现一个自定义的
MyList
类,但问题是我必须实现所有可能的
IList
方法,但我只需要对其中一些方法进行自定义实现,而不是所有方法。。或者还有其他方法吗?

您可以将列表保密,不向消费者公开。这样,消费者就无法修改您的列表

此外,通过使用IReadOnlyList,使用者甚至不需要添加或删除

private List<int> myList;
public IReadOnlyList<int> MyList => myList.ToArray();
私有列表myList;
public-IReadOnlyList-MyList=>MyList.ToArray();
但是,每次转换为数组都会带来性能损失。如果您不想浪费资源,并且绝对不能更改接口,则需要创建自己的IList实现:

public class MyClass: IMyClass {
    private IList<int> myInnerList;
    public IList<int> MyList { get; }


    MyClass() 
    {
        myInnerList = new List<int>();
        MyList = new ProtectedList(myInnerList);
    }

    public void AddToList(int newVal)
    {
        myInnerList.Add(newVal);
    }
}

/// <summary>
/// Encapsulates an IList in a way, so that you can only change it
/// through the original IList reference.
/// </summary>
class ProtectedList<T> : IList<T>, IReadOnlyList<T>
{
    private IList<T> innerList;
    public ProtectedList(IList<T> innerList) => this.innerList = innerList;

    public T this[int index]
    {
        get => innerList[index];
        set => throw new InvalidOperationException();
    }
    public int Count => innerList.Count;
    public bool IsReadOnly => true;
    public void Add(T item) => throw new InvalidOperationException();
    public void Clear() => throw new InvalidOperationException();
    public bool Contains(T item) => innerList.Contains(item);
    public void CopyTo(T[] array, int arrayIndex) => innerList.CopyTo(array, arrayIndex);
    public IEnumerator<T> GetEnumerator() => innerList.GetEnumerator();
    public int IndexOf(T item) => innerList.IndexOf(item);
    public void Insert(int index, T item) => throw new InvalidOperationException();
    public bool Remove(T item) => throw new InvalidOperationException();
    public void RemoveAt(int index) => throw new InvalidOperationException();
    IEnumerator IEnumerable.GetEnumerator() => innerList.GetEnumerator();
}
公共类MyClass:IMyClass{
私有IList myInnerList;
公共IList MyList{get;}
MyClass()
{
myInnerList=新列表();
MyList=新的ProtectedList(myInnerList);
}
公共无效地址列表(int newVal)
{
myInnerList.Add(newVal);
}
}
/// 
///以某种方式封装IList,以便您只能对其进行更改
///通过原始IList引用。
/// 
类ProtectedList:IList、IReadOnlyList
{
私有IList内部列表;
public ProtectedList(IList innerList)=>this.innerList=innerList;
公共T此[int索引]
{
get=>innerList[index];
set=>抛出新的InvalidOperationException();
}
public int Count=>innerList.Count;
公共bool IsReadOnly=>true;
public void Add(T项)=>抛出新的InvalidOperationException();
public void Clear()=>抛出新的InvalidOperationException();
public bool Contains(T项)=>innerList.Contains(项);
public void CopyTo(T[]数组,int arrayIndex)=>innerList.CopyTo(数组,arrayIndex);
public IEnumerator GetEnumerator()=>innerList.GetEnumerator();
public int IndexOf(T项)=>innerList.IndexOf(项);
public void Insert(int index,T item)=>抛出新的invalidoOperationException();
公共bool Remove(T项)=>抛出新的InvalidOperationException();
public void RemoveAt(int index)=>抛出新的invalidoOperationException();
IEnumerator IEnumerable.GetEnumerator()=>innerList.GetEnumerator();
}

}

您可以在
IList
周围创建一个包装器,实现
IList
接口。这个包装器将所有功能委托给它的内部
IList
,并且只禁止直接操作该列表。比如:

public MyList<T> : IList<T>
{
    private IList<T> innerList;
    public MyList(IList<T> innerList) { this.innerList = innerList; }

    // valid operations are just delegated to the inner list...
    public int Count { get { return innerList.Count; } }
    // those you want to prohibit either do nothing or throw - depends on your desired outcome
    public void Add(T item) { return; }

    // and so on ...
}
public MyList:IList
{
私有IList内部列表;
公共MyList(IList innerList){this.innerList=innerList;}
//有效的操作只是委派给内部列表。。。
public int Count{get{return innerList.Count;}}
//那些你想禁止的人要么什么也不做,要么扔——取决于你想要的结果
公共无效添加(T项){return;}
//等等。。。
}

既然您说您不能更改界面,那么您必须将该属性公开为public
IList
。即使显式实现接口(隐藏公共属性),也没有任何东西阻止用户将实例强制转换为接口类型以访问公共
IList
属性

但是,由于实现了
IList
接口,您可以使用它在私有列表周围创建只读包装,因此您可以通过public属性仅公开该只读包装,但将实际列表保持私有,从而防止用户更改它。例如:

interface IMyClass {
    IList<int> MyList { get; set; }
    void AddToList(int newVal);
}

public class MyClass: IMyClass {
    private readonly List<int> myPrivateList;

    public IList<int> MyList { get; set; }

    public MyClass()
    {
        // Create private list used internally
        myPrivateList = new List<int>();

        // Create read-only wrapper around myPrivateList used for the public MyList property
        MyList = new ReadOnlyCollection<int>(myPrivateList);
    }

    public void AddToList(int newVal)
    {
        // Use myPrivateList instead of MyList
        myPrivateList.Add(newVal);
    }
}
接口IMyClass{
IList MyList{get;set;}
无效地址列表(int newVal);
}
公共类MyClass:IMyClass{
私人只读列表myPrivateList;
公共IList MyList{get;set;}
公共MyClass()
{
//创建内部使用的私有列表
myPrivateList=新列表();
//围绕用于公共MyList属性的myPrivateList创建只读包装
MyList=新的只读集合(myPrivateList);
}
公共无效地址列表(int newVal)
{
//使用myPrivateList而不是MyList
myPrivateList.Add(newVal);
}
}

虽然这对其他开发人员来说可能有点误导,但我认为这样的解决方案应该在实现中正确记录。

您应该将MyList属性设置为私有。根据您的列表授予对只读列表的访问权限,并将您的列表设置为私有。。。我将采取相反的观点,并说:你根本不应该这样做。您将其视为“嘿,这打破了封装,允许任何人从任何地方设置我的列表。”但是。。。这就是界面所指示的。如果我正在编程并使用实现该接口的东西,我希望我可以一次添加一个项目,或者直接设置完整列表。如果你做了你想做的事情,你基本上是在违反合同——你让它的行为与界面上显示的不同