Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Как по "умному" переписать класс


Автор: Ch0bits 26.3.2006, 20:50
Код

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace ConsoleApplication1
{
    /// <summary>
    /// Позволяет хранить произвольные объекты и получать к ним доступ по имени
    /// </summary>
    public class SceneObjectsCollection
    {
        ArrayList Objects = new ArrayList();
        List<string> Names = new List<string>();

        /// <summary>
        /// Пихает объект в кучу
        /// </summary>
        /// <param name="Obj">Объект</param>
        /// <param name="Name">Имя</param>
        public bool Add(object Obj, string Name)
        {
            if (Names.IndexOf(Name) == -1)
            {
                Objects.Add(Obj);
                Names.Add(Name);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Получаем доступ к объекту по индексу
        /// </summary>
        /// <param name="Index">Индекс</param>
        public object this[int Index]
        {
            get
            {
                return Objects[Index];
            }
            set
            {
                Objects[Index] = value;
            }
        }

        /// <summary>
        /// Получаем доступ к объекту по имени
        /// </summary>
        /// <param name="Name">Назначенное объекту имя</param>
        /// <returns></returns>
        public object this[string Name]
        {
            get
            {
                int i = Names.IndexOf(Name);
                return Objects[i];
            }
            set
            {
                int i = Names.IndexOf(Name);
                Objects[i] = value;
            }
        }

        /// <summary>
        /// Удаляет объект из коллекции по индексу
        /// </summary>
        /// <param name="Index">Индекс</param>
        /// <returns>true - удачное удаление</returns>
        public bool Delete(int Index)
        {
            try
            {
                Names.RemoveAt(Index);
                Objects.RemoveAt(Index);
            }
            catch
            {
                return false; // Не удалось удалить объект
            }
            return true;
        }

        /// <summary>
        /// Удаляет объект из коллекции по имени
        /// </summary>
        /// <param name="Name"></param>
        /// <returns>true - удачное удаление</returns>
        public bool Delete(string Name)
        {
            try
            {
                int i = Names.IndexOf(Name);
                Names.RemoveAt(i);
                Objects.RemoveAt(i);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public int Count
        {
            get { return Objects.Count; }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SceneObjectsCollection S = new SceneObjectsCollection();
            S.Add("Hello World!", "1");
            S.Add("2 + 2 = 7", "2");
            S.Add("Vingrad rulezzz!", "3");
            
            // Доступ по индексу
            for(int i=0;i<S.Count;i++)
            {
                 Console.WriteLine(S[i] as string);
            }

            // Доступ по имени
            Console.WriteLine(S["3"] as string);

            Console.ReadKey();
        }
    }
}


Вот такая штука: осуществляет доступ к объектам по имени (имена не должны совпадать).
Как бы это привести к человеческому виду и чтобы можно было через foreach получать элементы? А то наворотил я тут... smile
smile

Автор: Void 26.3.2006, 21:17
Ch0bits, тебе обязательно нужен доступ по индексу? Если нет, то все что тебе нужно — это System.Collections.Generic.Dictionary<string, object>.

Автор: Ch0bits 26.3.2006, 21:41
Цитата(Void @ 26.3.2006, 21:17 Найти цитируемый пост)
тебе обязательно нужен доступ по индексу?

Да.

Автор: Void 26.3.2006, 22:34
Цитата(Ch0bits @ 26.3.2006, 23:41 Найти цитируемый пост)
тебе обязательно нужен доступ по индексу?

Да.

Рискну все-таки уточнить. Если индекс тебе нужен только для перебора всех объектов, то все равно можно обойтись Dictionary, потому что он реализует IEnumerable. Если же нужен именно индекс, можно сделать примерно так: завести маппинг строковых имен на индексы плюс индексируемый список или массив объектов. Чтобы обеспечить быстрое удаление по индексу, вместе с объектами в списке будем держать их имена. Если объекты удаляются нечасто, а оверхед по памяти критичен, можно этого и не делать.
Код

class IndexedDictionary<T> : IEnumerable<T>
{

    private class NameValuePair
    {
        public string name;
        public T value;

        public NameValuePair(string name, T value)
        {
            this.name = name;
            this.value = value;
        }
    }

    private IDictionary<string, int> entries_;
    private IList<NameValuePair> items_;

    public IndexedDictionary()
    {
        entries_ = new Dictionary<string, int>();
        items_ = new List<NameValuePair>();
    }

    public bool Add(string name, T item)
    {
        if (entries_.ContainsKey(name))
            return false;
        entries_[name] = items_.Count;
        items_.Add(new NameValuePair(name, item));
        return true;
    }

    public T this[int index]
    {
        get
        {
            return items_[index].value;
        }
        set
        {
            items_[index].value = value;
        }
    }

    public T this[string name]
    {
        get
        {
            return items_[entries_[name]].value;
        }
        set
        {
            items_[entries_[name]] = new NameValuePair(name, value);
        }
    }

    public bool Delete(int index)
    {
        try
        {
            string name = items_[index].name;
            items_.RemoveAt(index);
            entries_.Remove(name);
        }
        catch
        {
            return false;
        }
        return true;
    }

    public bool Delete(string name)
    {
        try
        {
            int index = entries_[name];
            items_.RemoveAt(index);
            entries_.Remove(name);
        }
        catch (KeyNotFoundException e)
        {
            return false;
        }
        return true;
    }

    public IEnumerator<T> GetEnumerator()
    {
        foreach (NameValuePair pair in items_)
            yield return pair.value;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        foreach (NameValuePair pair in items_)
            yield return pair.value;
    }

}

Автор: Ch0bits 26.3.2006, 22:48
Void
Круто пишешь. smile

Цитата(Void @ 26.3.2006, 22:34 Найти цитируемый пост)
нужен именно индекс

Да. Мне там всё нужно.

Вот сам прилепил работу с foreach.
Код

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace ConsoleApplication1
{
    /// <summary>
    /// Позволяет хранить произвольные объекты и получать к ним доступ по имени
    /// </summary>
    public class SceneObjectsCollection : IEnumerable

    {
        ArrayList Objects = new ArrayList();
        List<string> Names = new List<string>();

        /// <summary>
        /// Пихает объект в кучу
        /// </summary>
        /// <param name="Obj">Объект</param>
        /// <param name="Name">Имя</param>
        public bool Add(object Obj, string Name)
        {
            if (Names.IndexOf(Name) == -1)
            {
                Objects.Add(Obj);
                Names.Add(Name);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Получаем доступ к объекту по индексу
        /// </summary>
        /// <param name="Index">Индекс</param>
        public object this[int Index]
        {
            get { return Objects[Index]; }
            set { Objects[Index] = value; }
        }

        /// <summary>
        /// Получаем доступ к объекту по имени
        /// </summary>
        /// <param name="Name">Назначенное объекту имя</param>
        public object this[string Name]
        {
            get
            {
                int i = Names.IndexOf(Name);
                return Objects[i];
            }
            set
            {
                int i = Names.IndexOf(Name);
                Objects[i] = value;
            }
        }

        /// <summary>
        /// Удаляет объект из коллекции по индексу
        /// </summary>
        /// <param name="Index">Индекс</param>
        /// <returns>true - удачное удаление</returns>
        public bool Delete(int Index)
        {
            try
            {
                Names.RemoveAt(Index);
                Objects.RemoveAt(Index);
            }
            catch
            {
                return false; // Не удалось удалить объект
            }
            return true;
        }

        /// <summary>
        /// Удаляет объект из коллекции по имени
        /// </summary>
        /// <param name="Name">Имя объекта</param>
        /// <returns>true - удачное удаление</returns>
        public bool Delete(string Name)
        {
            try
            {
                int i = Names.IndexOf(Name);
                Names.RemoveAt(i);
                Objects.RemoveAt(i);
            }
            catch
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Возвращает количество элементов
        /// </summary>
        public int Count
        {
            get { return Objects.Count; }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }

        /// <summary>
        /// Внутренний класс-перечислитель
        /// </summary>
        private class Enumerator : IEnumerator
        {
            private SceneObjectsCollection soc;

            public Enumerator(SceneObjectsCollection soc)
            {
                this.soc = soc;
            }

            private int pos = -1;

            public object Current
            {
                get { return soc.Objects[pos]; }
            }

            public bool MoveNext()
            {
                if (pos < soc.Objects.Count-1)
                {
                    pos++;
                    return true;
                }
                else
                    return false;
            }

            public void Reset()
            {
                pos = -1;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SceneObjectsCollection S = new SceneObjectsCollection();
            S.Add("Hello World!", "1");
            S.Add("good morning!", "2");
            S.Add("Vingrad rulezzz", "3");
            S.Add("string", "123");

            S["123"] = "AAAAAA";
            S[0] = S[0] + " And " + S[1];

            // Перерь работает!
            foreach(object o in S)
                Console.WriteLine(o as string);

            Console.ReadKey();
        }
    }
}


Автор: Void 26.3.2006, 22:56
Цитата(Ch0bits @ 27.3.2006, 00:48 Найти цитируемый пост)
Вот сам прилепил работу с foreach.

Если ты пишешь на .NET 2.0, то эти извраты с ручным созданием IEnumerator ни к чему — пользуйся yield.
Добавлено @ 22:57
Чем мой вариант-то не устроил? Доступ по имени у тебя будет сильно тормозить на большом количестве объектов.

Автор: Ch0bits 26.3.2006, 22:57
Void
Аааа! Какой ты умный! smile Почему я не могу писать так-же как ты? smile


Цитата(Void @ 26.3.2006, 22:56 Найти цитируемый пост)
пользуйся yield

А чего это?
Добавлено @ 22:59
Цитата(Void @ 26.3.2006, 22:56 Найти цитируемый пост)
Чем мой вариант-то не устроил?

Я теперь им пользуюсь. smile

Автор: Void 26.3.2006, 23:28
Цитата(Ch0bits @ 27.3.2006, 00:57 Найти цитируемый пост)
пользуйся yield

А чего это?

См. http://windowssdk.msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_csref/html/f45331db-d595-46ec-9142-551d3d1eb1a7.asp.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)