Хорошо с решением @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)
Ну, самое простое - это заставить свойство возвращать объект, реализующий IList
.
Помните, что то, что объект реализует IList, не означает, что он сам является коллекцией, просто он реализует определенные методы.
Это технически неправильный способ использования 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.
Почему бы вашему классу не наследовать 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;
}
}
}
Я думаю, что дизайн, который вы опубликовали, - это правильный выбор, с той разницей, что я бы определил интерфейс:
public interface IIndexed<IndexT, ValueT>
{
ValueT this[IndexT i] { get; set; }
}
И для общих случаев я бы использовал класс, который вы поместили в исходном вопросе (который реализует этот интерфейс).
Было бы неплохо, если бы библиотека базовых классов предоставляла нам подходящий интерфейс, но это не так. Возвращать здесь IList было бы извращением.
Это не отвечает на ваш вопрос, но интересно отметить, что CIL поддерживает создание свойств, как вы описали - некоторые языки (например, F#) тоже позволяют определять их таким образом.
Индексатор this[]
в C# - это просто конкретный экземпляр одного из них, который переименовывается в Item
, когда вы собираете свое приложение. Компилятор C# знает, как читать только этот, поэтому если вы напишете "именованный индексатор" под названием Target
в библиотеке F# и попытаетесь использовать его в C#, единственный способ получить доступ к свойству - это методы ... get_Target(int)
и void set_Target(int, ...)
. Отстой.