How to adapt / create a method that receives an anonymous class in C #

4

I have a method in which one of the parameters is an object of an abstract class - ObjectMapper - whose purpose is to convert an object from one class to another from another class. Below, the method signature informs that the objectMapper will receive as input a DbDataReader and will return a generic object T

public T Select<T>(string query, ObjectMapper<T, DbDataReader> objectMapper)
{
    var reader = dbConnector.CreateCommand(query).ExecuteReader();

    try
    {
        return objectMapper.from(reader);
    }
    catch (Exception e)
    {
        throw e;
    }
    finally
    {
        reader.Close();
    }
}

As I come from the Java background, for cases that do not need to create a class, just use an anonymous class. However, it seems that C # does not provide this functionality, so I could invoke the method as below

Select<Pessoa>("SELECT * FROM PESSOA", new ObjectMapper<Pessoa, DbDataReader>() {
    public override Pessoa from(DbDataReader reader) {
        Pessoa p = new Pessoa();

        /** Populo o objeto p a partir do objeto DbDataReader **/

        return p;
    }
});

What should you do to adapt - or even create a new method - so that I can pass an "anonymous class" to the Select method?

UPDATE

The ObjectMapper class

public abstract class ObjectMapper<T, Source>
{
    public abstract T from(Source source);

    public static bool hasColumnName(DbDataReader reader, string columnName)
    {
        for (int i = 0; i < reader.FieldCount; i++)
        {
            if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase)) 
            {
                return true;
            }
        }

        return false;
    }

    /** Outros métodos utilitários **/ 
}

This class would be an adaptation of the RowMapper class, used by the Spring framework

link

    
asked by anonymous 17.09.2015 / 17:04

2 answers

3

In C # you can use a delegate to pass a function / method to another method.

C # provides some ready-to-use delegates .

If you just need to use static methods of the ObjectMapper class I suggest you do this:

Declare the method Select of the following form:

public T Select<T>(string query, Func<DbDataReader, T> from)
{
    var reader = dbConnector.CreateCommand(query).ExecuteReader();

    try
    {
        return from(reader);
    }
    catch (Exception e)
    {
        throw e;
    }
    finally
    {
        reader.Close();
    }
}

In the Select method, in addition to the string corresponding to SQL, a delegate is passed that receives a DbDataReader and returns an object of type T

This delegate is encapsulated using Func<T, TResult> .

To call the Select method do so:

Pessoa pessoa = Select("SELECT * FROM PESSOA", reader =>
    {
        Pessoa p = new Pessoa();

        /** Populo o objeto p a partir do objeto DbDataReader **/

        return p;
    });

The code between braces is what you want and you have access to DbDataReader through the variable reader

    
17.09.2015 / 18:53
1

If the goal is to provide a dynamic mapper for C #, there are already a few ready, like AutoMapper .

If the goal is to implement to learn, I can say that I have never seen this construct define the object and then implement the body of the function, all together, at least not in C #.

In its place, it would not define from as abstract. It would define virtual , allowing the derived classes to reimplement the method if necessary:

public abstract class ObjectMapper<T, TSource>
    where T: class, new()
    where TSource: DbDataReader
{
    public IEnumerable<T> From(TSource source)
    {
        if (source.HasRows)
        {
            while (source.Read())
            {
                var objeto = new T();
                for( int index = 0; index < source.FieldCount; index ++ )
                {
                    typeof(T).GetProperty(source.GetName(index)).SetValue(objeto, source.GetString(index));
                }

                yield return objeto;
            }
         }
    };

    public static bool hasColumnName(DbDataReader reader, string columnName)
    {
        for (int i = 0; i < reader.FieldCount; i++)
        {
            if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase)) 
            {
                return true;
            }
        }

        return false;
    }

    /** Outros métodos utilitários **/ 
}

This example is not exactly safe, but it would be a start.

    
17.09.2015 / 17:58