Member 13839622 Ответов: 2

Как получить доступ к полям объекта, хранящегося в списке<T>


Я храню объекты, в списке<t>. В моих функциях RemovePoolObject и GetPoolObject для работы. Но я не могу получить доступ к полям TestClass.

       #region ObjectPooler
       public class PooledObject<T>
       {
           public Func<T> ObjectInitializer { get; }

           public PooledObject(Func<T> objectInitializer) { ObjectInitializer = objectInitializer ?? throw new ArgumentNullException(nameof(objectInitializer)); }
       }

       public enum PoolAddMethod
       {
           None,
           SingleObject //Initialize Single Object
       }

       public class ObjectPooler<T>
       {
           public List<T> _deepEndObjects { get; set; }
           private PooledObject<T> _deepEndObject;

           public PoolAddMethod AddObjectMethod { get; set; }

           public ObjectPooler(PooledObject<T> pooledObject, PoolAddMethod addObjectMethod)
           {
               _deepEndObject = pooledObject ?? throw new ArgumentNullException(nameof(pooledObject));

               AddObjectMethod = addObjectMethod;

               _deepEndObjects = new List<T>();
           }

           public void AddPoolObject() { _deepEndObjects.Add(_deepEndObject.ObjectInitializer.Invoke()); }

           public void EmptyPool() { _deepEndObjects.Clear(); }

           public T GetPoolObject(string gGet = "")
           {
               //Return a object at given idx or in this case a given GUID

               //return _deepEndObjects.Find(x => x.g.ToString() == gGet);
               return default(T);
           }

           public void RemovePoolObject(string gRemove = "")
           {
               //Remove a object at given idx or in this case a given GUID

               //_deepEndObjects.Remove(_deepEndObjects.Find(x => x.g.ToString() == gRemove));
           }
       }
       #endregion

       public class TestClass
       {
           public Guid g = Guid.NewGuid(); //Just for testing. Real class would like an unique ID
       }

PooledObject<TestClass> _pooledObject;
       ObjectPooler<TestClass> objectPooler;

       public Form1()
       {
           InitializeComponent();

           _pooledObject = new PooledObject<TestClass>(() => ObjectAlloc<TestClass>.New());

           objectPooler = new ObjectPooler<TestClass>(_pooledObject, PoolAddMethod.SingleObject);
       }

       private void genbutton_Click(object sender, EventArgs e)
       {
           int iTag = Convert.ToInt32((sender as Control).Tag);

           switch (iTag)
           {
               case 0:
                   objectPooler.AddPoolObject();
                   break;
               case 1:
                   if (listView1.SelectedItems.Count > 0)
                   {
                       objectPooler.RemovePoolObject();
                       objectPooler._deepEndObjects.Remove(objectPooler._deepEndObjects.Find(x => x.g.ToString() == listView1.SelectedItems[0].Text));
                   }
                   break;
               case 2:
                   objectPooler.EmptyPool();
                   break;
               default:
                   break;
           }

           listView1.Clear();

           objectPooler._deepEndObjects.ForEach(x => listView1.Items.Add($"{x.g.ToString()}"));
       }


Что я уже пробовал:

_deepEndObjects.Remove(_deepEndObjects.Find(x => x.g.ToString() == gRemove));

2 Ответов

Рейтинг:
4

Richard Deeming

Если вам нужно получить доступ к свойствам или методам из вашего параметра универсального типа, самый простой вариант-заставить ваши типы реализовать интерфейс и ограничить параметр типа типами, которые реализуют этот интерфейс.

Например:

public interface IObjectWithId
{
    Guid ObjectId { get; }
}

public class TestClass : IObjectWithId
{
    public Guid ObjectId { get; } = Guid.NewGuid();
}

public class ObjectPooler<T> where T : IObjectWithId
{
    ...
    
    public T GetPoolObject(Guid objectId)
    {
        return _deepEndObjects.Find(x => x.ObjectId == objectId);
    }
    
    public bool RemovePoolObject(Guid objectId)
    {
        int numberOfObjectsRemoved = _deepEndObjects.RemoveAll(x => x.ObjectId == objectId);
        return numberOfObjectsRemoved != 0;
    }
}


NB: Пулы объектов часто вызываются из нескольких потоков одновременно. В настоящее время ваш код не является потокобезопасным. Если вы вызовете его из нескольких потоков, то в конечном итоге испортите состояние пула.

Если это проблема, вы можете посмотреть на использование параллельная коллекция[^]. Например:
Как создать пул объектов с помощью ConcurrentBag | Microsoft Docs[^]


Рейтинг:
18

Gerry Schmitz

Используйте GetHashCode() базового объекта для отслеживания "идентификаторов"ваших объектов.


Member 13839622

Йа... Это хорошая идея. Я мог бы, использовать это. Я использую здесь GUID, просто для тестирования. То, что мне здесь нужно, - это как вытащить каждый объект и использовать его или удалить.

Gerry Schmitz

Вам не нужно прибегать к обобщениям, когда вы имеете дело с "разными объектами", то есть List< object>и т. д. работает просто отлично для ваших очевидных требований.

Если и когда вам действительно нужно знать, то вы получаете его тип.