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;}
//等等。。。
}
既然您说您不能更改界面,那么您必须将该属性公开为publicIList
。即使显式实现接口(隐藏公共属性),也没有任何东西阻止用户将实例强制转换为接口类型以访问公共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属性设置为私有。根据您的列表授予对只读列表的访问权限,并将您的列表设置为私有。。。我将采取相反的观点,并说:你根本不应该这样做。您将其视为“嘿,这打破了封装,允许任何人从任何地方设置我的列表。”但是。。。这就是界面所指示的。如果我正在编程并使用实现该接口的东西,我希望我可以一次添加一个项目,或者直接设置完整列表。如果你做了你想做的事情,你基本上是在违反合同——你让它的行为与界面上显示的不同