从派生类创建只读通用列表

时间:2019-03-05 22:01:30

标签: c# dictionary generics

我正在为开发人员开发一个库,他们必须在其中创建一个继承自我创建的类的类。

此基类实质上是为开发人员管理对象的数组,但是开发人员可以指定他们希望基类管理的这些对象的类型。

因此,开发人员实质上只是告诉基类创建一个数组,然后仅对该数组具有只读访问权限。基类将(取决于应用程序的状态)在数组中添加或删除对象。

我一直坚持寻找合适的数据类型来存储这样的东西。我已经尝试过paintComponent(...)ref,但那无济于事。我最接近的是out,但是这个想法失败了,因为C#实际上只是将值复制到字典中,而不是引用或指向它。

这是我一起提出的一个简单例子:

Dictionary

输出:

    public static void Main()
    {
        Derived d = new Derived();
        d.InitBase();
        d.Init();
        d.CheckArray();
        d.AddElement<GenericObject>(new GenericObject{ i = 2 });
        d.CheckArray();
    }

    public class Base {
        Dictionary<Type, List<object>> ArrayReferences;

        public void InitBase() {
             ArrayReferences = new Dictionary<Type, List<object>>();
        }

        protected ReadOnlyCollection<T> RegisterArray<T>() {
            List<object> managedArray = new List<object>();
            ArrayReferences.Add(typeof(T), managedArray);
            return Array.AsReadOnly(managedArray.Select(s => (T)s).ToArray());
        }

        public void AddElement<T>(T obj) {
            ArrayReferences[typeof(T)].Add(obj);
        }

        public void RemoveElement<T>(T obj) {
            ArrayReferences[typeof(T)].Remove(obj);
        }
    }

    public class Derived: Base {
        ReadOnlyCollection<GenericObject> arr;
        public void Init() {
             arr = RegisterArray<GenericObject>();
        }
        public void CheckArray() {
            Console.WriteLine(arr.Count());
        }
    }

    public class GenericObject {
        public int i = 0;
    }

字典显然不像我希望的那样将值存储为引用。那么C#还有什么其他技术?或者这根本不可能?同样不确定0 0 会导致多少问题,所以我不敢走这条路。

3 个答案:

答案 0 :(得分:1)

虽然我认为有解决此问题的更好方法,但是可以做到。

存储List<object>而不是存储which isn't compatibleList<T>的{​​{1}}引用。在object中使用静态值来保存Base,以便所有派生类都有一个Dictionary

Dictionary

PS另外,在使用public static void Main() { var d = new Derived(); d.CheckCollection("d before AddElement"); d.AddElement(new GenericObject { i = 2 }); d.CheckCollection("d after AddElement"); Console.WriteLine($"ListCount = {Base.ListCount}"); var d2 = new Derived2(); d2.CheckCollection("d2 before AddElement"); d2.AddElement(new GenericObject2 { i = 4 }); d2.AddElement(new GenericObject2 { i = 5 }); d2.CheckCollection("d2 after AddElement"); Console.WriteLine($"ListCount = {Base.ListCount}"); } public class Base { static Dictionary<Type, object> ListReferences = new Dictionary<Type, object>(); public static int ListCount => ListReferences.Count(); protected ReadOnlyCollection<T> RegisterList<T>() { var managedList = new List<T>(); ListReferences.Add(typeof(T), managedList); return managedList.AsReadOnly(); } public void AddElement<T>(T obj) { ((List<T>)ListReferences[typeof(T)]).Add(obj); } public void RemoveElement<T>(T obj) { ((List<T>)ListReferences[typeof(T)]).Remove(obj); } } public class Derived : Base { ReadOnlyCollection<GenericObject> roc; public Derived() { roc = RegisterList<GenericObject>(); } public void CheckCollection(string msg) { Console.WriteLine(msg); Console.WriteLine(roc.Count()); } } public class Derived2 : Base { ReadOnlyCollection<GenericObject2> roc; public Derived2() { roc = RegisterList<GenericObject2>(); } public void CheckCollection(string msg) { Console.WriteLine(msg); Console.WriteLine(roc.Count()); } } public class GenericObject { public int i = 0; } public class GenericObject2 { public int i = 0; } 时,请勿使用“数组”来命名方法和变量。

答案 1 :(得分:0)

您编写的以下代码会在创建列表时复制列表-因此无论之后添加到列表中的内容如何,​​列表始终为空。

List<object> managedArray = new List<object>();
ArrayReferences.Add(typeof(T), managedArray);
return Array.AsReadOnly(managedArray.Select(s => (T)s).ToArray());

这是您应该如何编写代码以获取所需内容的方法:

public static void Main()
{
    Derived d = new Derived();
    Console.WriteLine(d.AsReadOnly().Count);
    d.AddElement(new GenericObject { i = 2 });
    Console.WriteLine(d.AsReadOnly().Count);
}

public class Base<T>
{
    List<T> _items = new List<T>();

    public ReadOnlyCollection<T> AsReadOnly()
    {
        return Array.AsReadOnly(_items.ToArray());
    }

    public void AddElement(T obj)
    {
        _items.Add(obj);
    }

    public void RemoveElement(T obj)
    {
        _items.Remove(obj);
    }
}

public class Derived : Base<GenericObject>
{
}

public class GenericObject
{
    public int i = 0;
}

输出:

0
1

现在,值得考虑的是List<T>已经有一个AsReadOnly()方法,因此您可以简单地编写以下代码:

public static void Main()
{
    var d = new List<GenericObject>();
    Console.WriteLine(d.AsReadOnly().Count);
    d.Add(new GenericObject { i = 2 });
    Console.WriteLine(d.AsReadOnly().Count);
}

public class GenericObject
{
    public int i = 0;
}

那也行。


在这里,您应该这样做以一次容纳多个列表。不需要继承。

public static void Main()
{
    Repository r = new Repository();
    Console.WriteLine(r.AsReadOnly<GenericObject>().Count);
    r.AddElement<GenericObject>(new GenericObject { i = 2 });
    Console.WriteLine(r.AsReadOnly<GenericObject>().Count);
}

public class Repository
{
    private Dictionary<Type, object> _references = new Dictionary<Type, object>();

    private void Ensure<T>()
    {
        if (!_references.ContainsKey(typeof(T)))
        {
            _references[typeof(T)] = new List<T>();
        }
    }

    public ReadOnlyCollection<T> AsReadOnly<T>()
    {
        this.Ensure<T>();
        return (_references[typeof(T)] as List<T>).AsReadOnly();
    }

    public void AddElement<T>(T obj)
    {
        this.Ensure<T>();
        (_references[typeof(T)] as List<T>).Add(obj);
    }

    public void RemoveElement<T>(T obj)
    {
        this.Ensure<T>();
        (_references[typeof(T)] as List<T>).Remove(obj);
    }
}

public class GenericObject
{
    public int i = 0;
}

答案 2 :(得分:-1)

在您的基类中(或封装类,如果您选择那样的话):

    protected ReadOnlyCollection<T> GetSnapshot<T>() {
        return Array.AsReadOnly(ArrayReferences[typeof(T)].Select(s => (T)s).ToArray());
    }

然后,您还需要添加其他方法来查看数据,例如获得计数:

    protected int GetCount<T>() {
        return ArrayReferences[typeof(T)].Count;
    }