Подойдут ли методы расширения для индексаторов?

Подойдут ли методы расширения для индексаторов?

Я играл с некоторым кодом, который повторно гидратирует POCO.

Код выполняет итерацию по строкам, возвращаемым из SqlDataReader, и использует отражение для назначения свойств из значений столбцов. В моем стеке вызовов у меня был код такой строки: -

poco.Set("Surname", "Smith"); // uses extension method ...

Метод Set был написан как метод расширения.

Было бы здорово написать такой код

poco["Surname"] = "Smith";  // extension methods for indexers ?

т.е. я хотел написать метод расширения для индексатора

Есть ли веская причина, по которой .Net не имеет методов расширения для индексаторов? Есть ли у других хорошее применение индексаторам методов расширения?

в стороне ... Если бы мы могли писать методы расширения для индексаторов, мы могли бы написать такой код ...

var poco = PocoFactory();  
    poco.Surname = “Smith”; // is this JavaScript ...
    poco[Surname] = “Smith” ; // … or is this c# or both

Некоторые фрагменты моего кода

/////////////////////////////////////////////
// Client calling code
IDab dab = DabFactory.Create( "Northwind" );
string sql = @"select * from Customers ";
var persons = dab.ExecuteReader<NorthwindCustomer>(sql);
if (dab != null{
   Assert.That(persons[0].CustomerID , Is.EqualTo("ALFKI"));}
/////////////////////////////////////////////
List<T> IDab.ExecuteReader<T>(string commandText) 
{
    List<T> pocos = new List<T>();
    // setup connection
    SqlDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
    while (reader.Read())
    {
            Dictionary<string, int> colMappings = null ;
            if (colMappings == null){
                colMappings = reader.GetSqlDataReaderColumnMappings();}
            T poco = new T();
            poco.DbToMem<T>(reader, colMappings);
            pocos.Add(poco);
        }
    }
    // connection cleanup ...
    return pocos ;
}

// the set extension method signature
public static void Set<T>(this T thisClientObject, string thisPropertyName, object newValue) where T : class

Ответов (2)

Для регидратации Pocos я бы рекомендовал взглянуть на пакет AutoMapper Nuget. Это действительно просто и значительно сокращает объем кода.

Индексаторы имеют много общего со свойствами (под капотом индексатор - это свойство с индексом), а свойства расширения не существуют. Договорились, будут сценарии, где они пригодятся.

Re the scenario presented - in some ways, this is quite like dynamic . Of course, if you declare an interface that has a string indexer, then your reader-code could use it directly - but it would be a lot of unnecessary work to implement this interface repeatedly!

Re the extension method; does this use regular reflection? You might want to look at tricks like HyperDescriptor, which might save a lot of CPU time if you are doing lots of this. Typical usage would then be:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
while (reader.Read())
{
     T poco = new T();
     // abbreviated...
     (per prop)
        props[propName].SetValue(poco, cellValue);
}

You can optimise this further by looking at the returned columns first (once per grid, not per row), and only accessing matched columns...

Or alternatively, look at ORM tools; Expression can also be used to do data reading (I have a complete example of this somewhere on usenet, for DbLinq)