Легкое создание свойств, которые поддерживают индексацию в C#

Хорошо с решением @kajal, но просто хочу добавить другую опцию, используя css.

Использование CSS:

panels = driver.find_elements_by_css_selector('.panel-content')
for panelNum in range(len(panels)):
    #get the divs count
    panelDivs = len(panels[panelNum].find_elements_by_css_selector("div.row.ehi-pd"))
    print str(panelNum+1) + " panel-content:" + str(panelDivs)
27
задан Community 23 May 2017 в 12:17
поделиться

5 ответов

Ну, самое простое - это заставить свойство возвращать объект, реализующий IList.

Помните, что то, что объект реализует IList, не означает, что он сам является коллекцией, просто он реализует определенные методы.

8
ответ дан 28 November 2019 в 05:35
поделиться

Это технически неправильный способ использования StackOverflow, но я посчитал вашу идею настолько полезной, что расширил ее. Я думал, что это сэкономит людям время, если я опубликую то, что я придумал, и пример того, как его использовать.

Во-первых, мне нужно было иметь возможность поддерживать свойства get-only и set-only, поэтому я немного изменил ваш код для этих сценариев:

Get and Set ( очень незначительные изменения):

public class IndexedProperty<TIndex, TValue>
{
    readonly Action<TIndex, TValue> SetAction;
    readonly Func<TIndex, TValue> GetFunc;

    public IndexedProperty(Func<TIndex, TValue> getFunc, Action<TIndex, TValue> setAction)
    {
        this.GetFunc = getFunc;
        this.SetAction = setAction;
    }

    public TValue this[TIndex i]
    {
        get
        {
            return GetFunc(i);
        }
        set
        {
            SetAction(i, value);
        }
    }
}

Получить только:

public class ReadOnlyIndexedProperty<TIndex, TValue>
{
    readonly Func<TIndex, TValue> GetFunc;

    public ReadOnlyIndexedProperty(Func<TIndex, TValue> getFunc)
    {
        this.GetFunc = getFunc;
    }

    public TValue this[TIndex i]
    {
        get
        {
            return GetFunc(i);
        }
    }
}

Установить только:

public class WriteOnlyIndexedProperty<TIndex, TValue>
{
    readonly Action<TIndex, TValue> SetAction;

    public WriteOnlyIndexedProperty(Action<TIndex, TValue> setAction)
    {
        this.SetAction = setAction;
    }

    public TValue this[TIndex i]
    {
        set 
        {
            SetAction(i, value);
        }
    }
}

Пример

Вот простой пример использования. Я наследую от Collection и создаю именованный индексатор, как его назвал Джон Скит. Этот пример должен быть простым, а не практичным:

public class ExampleCollection<T> : Collection<T>
{
    public IndexedProperty<int, T> ExampleProperty
    {
        get
        {
            return new IndexedProperty<int, T>(GetIndex, SetIndex);
        }
    }

    private T GetIndex(int index)
    {
        return this[index];
    }
    private void SetIndex(int index, T value)
    {
        this[index] = value;
    }
}

ExampleCollection in the Wild

Этот наскоро построенный модульный тест показывает, как он выглядит, когда вы ExampleCollection в project:

[TestClass]
public class IndexPropertyTests
{
    [TestMethod]
    public void IndexPropertyTest()
    {
        var MyExample = new ExampleCollection<string>();
        MyExample.Add("a");
        MyExample.Add("b");

        Assert.IsTrue(MyExample.ExampleProperty[0] == "a");
        Assert.IsTrue(MyExample.ExampleProperty[1] == "b");

        MyExample.ExampleProperty[0] = "c";

        Assert.IsTrue(MyExample.ExampleProperty[0] == "c");

    }
}

Наконец, если вы хотите использовать версии только для получения и только для набора, это выглядит так:

    public ReadOnlyIndexedProperty<int, T> ExampleProperty
    {
        get
        {
            return new ReadOnlyIndexedProperty<int, T>(GetIndex);
        }
    }

Или:

    public WriteOnlyIndexedProperty<int, T> ExampleProperty
    {
        get
        {
            return new WriteOnlyIndexedProperty<int, T>(SetIndex);
        }
    }

В обоих случаях результат работает точно так, как вы ожидаете, что будет работать только свойство get-only / set-only.

11
ответ дан Brian MacKay 28 November 2019 в 05:35
поделиться

Почему бы вашему классу не наследовать IList, тогда вы можете просто использовать индекс и добавить к нему свои собственные свойства. Хотя у вас все еще есть функции «Добавить и удалить», их нечестно не использовать. Кроме того, вам может быть полезно иметь их в дальнейшем.

Для получения дополнительной информации о списках и массивах, ознакомьтесь: Что лучше использовать массив или список? < >?

РЕДАКТИРОВАТЬ:

В MSDN есть статья о свойствах индекса, на которую вы можете взглянуть. Не кажется сложным, просто утомительно.

http://msdn.microsoft.com/en-us/library/aa288464 (VS.71) .aspx

Существует еще один вариант, в котором можно создать альтернативный вариант Add. метод, но в зависимости от типа объекта ваш метод add может вызываться не всегда. Объяснено здесь:

Как переопределить метод Add List < T > в C #?

РЕДАКТИРОВАТЬ 2: Похож на первый пост

Почему у вас нет скрытого списка объектов в вашем классе, а затем просто создайте свои собственные методы для получения данных. Таким образом, «Добавить» и «Удалить» не отображаются, и список уже проиндексирован.

Также, что вы подразумеваете под "именованным индексатором", вы ищете эквивалент строки ["My_Column_Name"]. Я нашел статью MSDN, которая может оказаться полезной, так как она показывает основной способ реализации этого свойства.

http://msdn.microsoft.com/en-us/library/146h6tk5.aspx

class Test
    {
        private List<T> index;
        public T this[string name]{ get; set; }
        public T this[int i]
        {
            get
            {
                return index[i];
            }
            set
            {
                index[i] = value;
            }
        }
    }
3
ответ дан Community 28 November 2019 в 05:35
поделиться

Я думаю, что дизайн, который вы опубликовали, - это правильный выбор, с той разницей, что я бы определил интерфейс:

public interface IIndexed<IndexT, ValueT>
{
    ValueT this[IndexT i] { get; set; }
}

И для общих случаев я бы использовал класс, который вы поместили в исходном вопросе (который реализует этот интерфейс).

Было бы неплохо, если бы библиотека базовых классов предоставляла нам подходящий интерфейс, но это не так. Возвращать здесь IList было бы извращением.

7
ответ дан 28 November 2019 в 05:35
поделиться

Это не отвечает на ваш вопрос, но интересно отметить, что CIL поддерживает создание свойств, как вы описали - некоторые языки (например, F#) тоже позволяют определять их таким образом.

Индексатор this[] в C# - это просто конкретный экземпляр одного из них, который переименовывается в Item, когда вы собираете свое приложение. Компилятор C# знает, как читать только этот, поэтому если вы напишете "именованный индексатор" под названием Target в библиотеке F# и попытаетесь использовать его в C#, единственный способ получить доступ к свойству - это методы ... get_Target(int) и void set_Target(int, ...). Отстой.

4
ответ дан 28 November 2019 в 05:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: