Как создать и установить свойства динамического типа с помощью System.Linq.Expressions - PullRequest
0 голосов
/ 11 декабря 2018

Я пишу SQL Data Mapper, который отображал бы запросы на динамические типы (я уже испытывал отображение sql на строго типизированные объекты посредством отражения)

На этот раз я хочу сделать вызов sql, а затем вернутьIenumerable.

Это то, что у меня пока есть:

public class DynamicMapper 
{
    private class ReaderColumnMap
    {
        public string Column { get; }
        public Type Type { get; }

        public ReaderColumnMap(string column, Type type)
        {
            Column = column;
            Type = type;
        }
    }

    private Func<IDataReader, dynamic> MappingMethod;

    public DynamicMapper(IDataReader schemaSource)
    {
        MappingMethod = CreateMapper(schemaSource);
    }

    private Func<IDataReader, dynamic> CreateMapper(IDataReader reader)
    {
        IDictionary<int, ReaderColumnMap> propertyMappingsCache = new Dictionary<int, ReaderColumnMap>();

        //The schema of sql table involves the column name and data type for each columns.
        DataTable schema = reader.GetSchemaTable(); 


        DataColumnCollection dataColumns = schema.Columns;

        //Gets the column name ordinal and data type ordinal

        int nameColumn = dataColumns["ColumnName"].Ordinal;

        int typeColumn = dataColumns["DataType"].Ordinal;

        int ordinalColumn = dataColumns["ColumnOrdinal"].Ordinal;

        DataRowCollection schemaRows = schema.Rows;

        int schemaRowCount = schemaRows.Count - 1;

        //Populates the property mappings
        for (int i = schemaRowCount; i != -1; --i)
        {
            DataRow row = schemaRows[i];
            string name = row[nameColumn].ToString();
            Type type = Type.GetType(row[typeColumn].ToString());
            int ordinal = Convert.ToInt32(row[ordinalColumn]);
            propertyMappingsCache.Add(ordinal, new ReaderColumnMap(name, type));
        }

        //Use expression tree here to create dynamic object (new() { Prop1 = "prop1", Prop2 = prop2... })

        //Dictionary sample:
        //Id = System.Int64
        //Name = System.String
        //Birthdate = System.DateTime

        //Target Expression:
        //dynamic instance = new (){
        //  Id = (System.Int64)reader[0];
        //  Name = (System.String)reader[1];
        //  Birthdate = (System.DateTime)reader[2];
        //}

        var expressions = new List<Expression>();

        var fxParameterExpression = Expression.Parameter(typeof(IDataReader), "reader");

        //Compiler error: the typeof operator cannot be used on the dynamic type
        var variableExpression = Expression.Variable(typeof(dynamic), "instance"); //dynamic instance = new ()

        //Compiler error: the typeof operator cannot be used on the dynamic type
        var instantiationExpression = Expression.New(typeof(dynamic));

        var assignExpression = Expression.Assign(variableExpression, instantiationExpression);

        var indexer = typeof(IDataReader).GetProperty("Item", new[] { typeof(int) }); // []

        expressions.Add(assignExpression);

        int propertyCount = propertyMappingsCache.Count - 1;

        for(int i = propertyCount; i != -1; --i)
        {
            //Get property details from mappingsCache (string property name and Type of property)
            //to create property
        }


        return null;
    }

    public dynamic CreateMappedInstance(IDataReader reader)
    {
        return MappingMethod.Invoke(reader);
    }


}

Но компилятор не позволяет мне создавать экземпляры динамического типа: оператор typeof нельзя использовать для динамического типа

Я планирую вызвать его в модуле sql следующим образом:

public class SqlCaller
{
    private readonly ISqlProvider sqlProvider;

    public SqlCaller(ISqlProvider sqlProvider)
    {
        this.sqlProvider = sqlProvider ?? throw new ArgumentNullException("sqlProvider");
    }

    public DataTable Query(string queryString)...

    public DataTable Query(DbCommand command)...

    public DataTable GetSchema(string queryString)...

    public int ExecuteNonQuery(DbCommand command)...

    public int ExecuteNonQuery(string commandString)...

    public object ExecuteScalar(string queryString)...

    public object ExecuteScalar(DbCommand command)...

    public bool ExecuteTransaction(IEnumerable<DbCommand> commands)...

    [Obsolete]
    public IEnumerable<T> Get<T>(Func<IDataReader, List<T>> mappingMethod, string query)...

    [Obsolete]
    public IEnumerable<T> Get<T>(Func<IDataReader, List<T>> mappingMethod, DbCommand command)...

    public IEnumerable<T> Get<T>(string query) where T : class, new()...

    public IEnumerable<T> Get<T>(DbCommand command) where T : class, new()...

    public IEnumerable<T> Get<T>(IDataMapper<T> dataMapper, DbCommand command) where T : class, new()...

    public IEnumerable<dynamic> GetDynamic(string commandString)
    {
        return GetDynamic(sqlProvider.CreateCommand(commandString));
    }

    public IEnumerable<dynamic> GetDynamic(DbCommand command)
    {
        List<dynamic> temp = new List<dynamic>();

        using (DbConnection connection = sqlProvider.CreateConnection())
        {
            command.Connection = connection;

            try
            {
                command.Connection.Open();

                IDataReader reader = command.ExecuteReader();

                var watch = Stopwatch.StartNew();

                DynamicMapper mapper = new DynamicMapper(reader);

                while(reader.Read()) temp.Add(mapper.CreateMappedInstance(reader));

                watch.Stop();
            }
            catch
            {
                throw;
            }
            finally
            {
                command.Connection.Close();
            }
        }

        return temp;
    }
}
  • Как создать экземпляр динамического типа в дереве выражений
  • Как установить значения свойств динамическоговведите внутри дерева выражений
...