替代反射 [英] Alternative to reflection

查看:116
本文介绍了替代反射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个泛型和反射非常少的以经验。我认为这样从下面的示例是,它需要太多的时间来执行。有没有办法让我实现以下不使用反射。



情景
我上是通用的方法工作。它需要传递给它一个类的实例,并从所有的属性使SqlParameters。以下是转换C#类型的DbType的SqlDbType名为商店泛型方法,还有一方法的代码。

 名单,LT ;&SqlParameter的GT;参数=新的List<&SqlParameter的GT;(); 
公共T商店< T>(T T)
{$ B $型B型= t.GetType();
的PropertyInfo []道具=(t.GetType())的GetProperties();
的foreach(的PropertyInfo p在道具)
{
的SqlParameter参数=新的SqlParameter();
型propType = p.PropertyType;
如果(propType.BaseType.Name.Equals(值类型)|| propType.BaseType.Name.Equals(阵列))
{
param.SqlDbType = GetDBType(propType) ; //例如。启用公共BOOL {获取;设置;}或公共​​字节[] {IMG获取;集;}
}
,否则如果(propType.BaseType.Name.Equals(对象))​​
{
如果(propType.Name.Equals(字符串))//字符串值
param.SqlDbType = GetDBType(propType);
,否则
{
动态D = p.GetValue(T,NULL); //为referrences例如公共ClassA的OBJ {获取;集;}
商店和LT;动态>(四)
}
}
param.ParameterName = p.Name;
parameters.Add(参数);
}
返回吨;
}



// mehthod从类型得到的DbType或SqlDbType ...
私人SqlDbType GetDBType(System.Type的类型)
{
的SqlParameter参数;
System.ComponentModel.TypeConverter TC;
参数=新的SqlParameter();
TC = System.ComponentModel.TypeDescriptor.GetConverter(param.DbType);
如果(tc.CanConvertFrom(类型))
{
param.DbType =(DbType之)tc.ConvertFrom(type.Name);
}
,否则
{
//试图强行转换

{
param.DbType =(DbType之)tc.ConvertFrom( type.Name);
}
赶上(例外五)
{
开关(type.Name)
{
案字符:
param.SqlDbType = SqlDbType.Char;
中断;
案为SByte:
param.SqlDbType = SqlDbType.SmallInt;
中断;
案UINT16:
param.SqlDbType = SqlDbType.SmallInt;
中断;
案UInt32的:
param.SqlDbType = SqlDbType.Int;
中断;
案UINT64:
param.SqlDbType = SqlDbType.Decimal;
中断;
案字节[]:
param.SqlDbType = SqlDbType.Binary;
中断;
}
}
}
返回param.SqlDbType;
}

要叫我的方法假设我有2类如下

 公共类clsParent 
{
公众诠释PID {搞定;组; }
公共字节[] {pImage获得;组; }
公共字符串PNAME {搞定;组; }
}



公共类clsChild
{
公共小数childID的{搞定;组; }
公共字符串childName {搞定;组; }
公共clsParent父{搞定;组; }
}

和这是一个呼叫


clsParent p值=新clsParent();
p.pID = 101;
p.pImage =新的字节[1000];
p.pName =约翰;
clsChild C =新clsChild();
c.childId = 1;
c.childName =一个;
c.parent = P;

商店和LT; clsChild>(C);


解决方案

如果你想摆脱反思,你可能找到下面的代码灵感。



下面所有访问对象在数据库中存储,以及SQL属性值分配是由一个运行时编译表达式处理从数据类型建立。



保持的值的表被假定为测试和字段名称被假定为等同于属性值。



有关每个属性一个映射< T> 构造。这将举行一个包含数据库字段,字段名 A 的SqlParameter 这应该是正确插入SQL 插入语句(在例如),最后如果包含编译动作,即可以利用输入的一个实例 T 对象,并赋值给 SqlParameters 属性。这些映射的集合构建在映射器下完成的; T> 类。代码是内联的说明。



最后,方法显示了如何将东西绑在一起。

 使用系统; 
使用System.Collections.Generic;
使用System.Data.SqlClient的;使用System.Diagnostics程序
;
使用System.Linq的;使用System.Linq.Expressions
;

命名空间ExpTest
{
类节目
{
公共类映射< T>
{
公共映射(字符串字段名,SqlParameter的SqlParameter的,动作< T,SqlParameter的>分配器)
{
字段名=字段名;
的SqlParameter =的SqlParameter;
SqlParameterAssignment =分配器;
}
公共字符串字段名{获得;私人集; }
公众的SqlParameter的SqlParameter {搞定;私人集; }
公共动作< T,SqlParameter的> SqlParameterAssignment {搞定;私人集; }
}

公共类映射< T>
{
公开的IEnumerable<映射< T>> GetMappingElements()
{
的foreach(在typeof运算变种reflectionProperty(T)的.GetProperties())
{
//输入参数来创建的分配动作
变种存取= Expression.Parameter(typeof运算(T),输入);
VAR sqlParmAccessor = Expression.Parameter(typeof运算(的SqlParameter),sqlParm);

//访问属性(后编,但在使用反射来定位属性)
VAR财产= Expression.Property(访问,reflectionProperty);

//把财产以确保它是分配给SqlProperty.Value
//应该包含分支为DBNull.Value时财产== NULL
VAR castPropertyToObject = Expression.Convert (财产的typeof(对象));


//的SQL参数
变种sqlParm =新的SqlParameter(reflectionProperty.Name,NULL);用于分配的动作
VAR sqlValueProp = Expression.Property(sqlParmAccessor,值)

//输入参数;

//表达分配从输入对象
//给SQL参数'值'属性
变种的DBNull = Expression.Constant(DBNull.Value)检索财产;
VAR COALESCE = Expression.Coalesce(castPropertyToObject,为DBNull);
VAR分配= Expression.Assign(sqlValueProp,COALESCE);

//编译付诸行动(消除反射,使真正的CLR对象)
VAR分配器= Expression.Lambda<作用< T,SqlParameter的>>(分配,访问,sqlParmAccessor).Compile ();

收益率的回报
新的映射下&; T>(reflectionProperty.Name,//表名
sqlParm,//构建的SQL参数
分配器); //该行动从输入<分配; T>

}
}
}

公共静态无效的主要(字串[] args)
{
VAR sqlStuff =(新映射器lt;数据>()GetMappingElements())了ToList()。

变种sqlFieldsList =的string.join(,,sqlStuff.Select(X => x.FieldName));
变种sqlValuesList =的string.join(,,sqlStuff.Select(X =>'@'+ x.SqlParameter.ParameterName));

VAR sqlStmt =的String.Format(INSERT INTO测试({0})VALUES({1}),sqlFieldsList,sqlValuesList);

VAR数据对象= Enumerable.Range(1,100)。选择(ID =>新建数据{美孚= 1.0 / ID,ID = ID,标题= NULL});

变种SW = Stopwatch.StartNew();

使用(SqlConnection的CNN =新的SqlConnection(@服务器= .\sqlexpress;数据库=测试;集成安全性= SSPI))
{
cnn.Open() ;

的SqlCommand CMD =新的SqlCommand(sqlStmt,美国有线电视新闻网)
cmd.Parameters.AddRange(sqlStuff.Select(X => x.SqlParameter).ToArray());

dataObjects.ToList()
.ForEach(DTO =>
{
sqlStuff.ForEach(X => x.SqlParameterAssignment(DTO,x.SqlParameter ));
cmd.ExecuteNonQuery();
});
}


Console.WriteLine(完成的:+ sw.Elapsed);
}
}

公共类数据
{
公共字符串名称{搞定;组; }
公众诠释ID {搞定;组; }
公共双富{搞定;组; }
}
}


I have very less experiece with Generics and Reflection. What I assumed so for from the following sample is that it takes too much time to perform. Is there a way so that i accomplish the following without using reflection..

SCENARIO I am working on a method which is generic. it takes an instance of a class passed to it and make SqlParameters from all of the properties. following is the code for generic method called "Store", and one more method that converts c# type to SqlDbType of DbType.

        List<SqlParameter> parameters = new List<SqlParameter>();
        public T Store<T>(T t)
        {
            Type type = t.GetType();
            PropertyInfo[] props = (t.GetType()).GetProperties();
            foreach (PropertyInfo p in props)
            {
                SqlParameter param = new SqlParameter();
                Type propType = p.PropertyType;
                if (propType.BaseType.Name.Equals("ValueType") || propType.BaseType.Name.Equals("Array"))
                {
                    param.SqlDbType = GetDBType(propType); //e.g. public bool enabled{get;set;} OR public byte[] img{get;set;}
                }
                else if (propType.BaseType.Name.Equals("Object"))
                {
                    if (propType.Name.Equals("String"))// for string values
                        param.SqlDbType = GetDBType(propType);
                    else
                    {
                        dynamic d = p.GetValue(t, null); // for referrences e.g. public ClassA obj{get;set;}
                        Store<dynamic>(d);
                    }
                }
                param.ParameterName = p.Name;
                parameters.Add(param);
            }
            return t;
        }



        // mehthod for getting the DbType OR SqlDbType from the type...
        private SqlDbType GetDBType(System.Type type)
        {
            SqlParameter param;
            System.ComponentModel.TypeConverter tc;
            param = new SqlParameter();
            tc = System.ComponentModel.TypeDescriptor.GetConverter(param.DbType);
            if (tc.CanConvertFrom(type))
            {
                param.DbType = (DbType)tc.ConvertFrom(type.Name);
            }
            else
            {
                // try to forcefully convert
                try
                {
                    param.DbType = (DbType)tc.ConvertFrom(type.Name);
                }
                catch (Exception e)
                {
                    switch (type.Name)
                    {
                        case "Char":
                            param.SqlDbType = SqlDbType.Char;
                            break;
                        case "SByte":
                            param.SqlDbType = SqlDbType.SmallInt;
                            break;
                        case "UInt16":
                            param.SqlDbType = SqlDbType.SmallInt;
                            break;
                        case "UInt32":
                            param.SqlDbType = SqlDbType.Int;
                            break;
                        case "UInt64":
                            param.SqlDbType = SqlDbType.Decimal;
                            break;
                        case "Byte[]":
                            param.SqlDbType = SqlDbType.Binary;
                            break;
                    }
                }
            }
            return param.SqlDbType;
        }

To call my method suppose i have 2 classes as following

public class clsParent
{
    public int pID { get; set; }
    public byte[] pImage { get; set; }
    public string pName { get; set; }
}

and

public class clsChild
{
    public decimal childId { get; set; }
    public string childName { get; set; }
    public clsParent parent { get; set; }
}

and this is a call 


clsParent p = new clsParent();
p.pID = 101;
p.pImage = new byte[1000];
p.pName = "John";
clsChild c = new clsChild();
c.childId = 1;
c.childName = "a";
c.parent = p;

Store<clsChild>(c);

解决方案

If you want to get rid of reflection, you may find inspiration in the code below.

Here all access to objects to store in database as well as the sql property value assignment is handled by a runtime compiled expression build from the data type.

The table holding the values is assumed to be test and the field names are assumed to be identical to the property values.

For each property a Mapping<T> is constructed. It will hold a FieldName containing the database field, a SqlParameter which is supposed to be inserted correctly into a SQL INSERT statement (example in main) and finally if contains the compiled action, that can take an instance of the input T object and assign the value to the SqlParameters property Value. Construction of a collection of these mappings are done in the Mapper<T> class. Code is inlined for explanation.

Finally the main method shows how to bind the stuff together.

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;

namespace ExpTest
{
    class Program
    {
        public class Mapping<T>
        {
            public Mapping(string fieldname, SqlParameter sqlParameter, Action<T, SqlParameter> assigner)
            {
                FieldName = fieldname;
                SqlParameter = sqlParameter;
                SqlParameterAssignment = assigner;
            }
            public string FieldName { get; private set; }
            public SqlParameter SqlParameter { get; private set; }
            public Action<T, SqlParameter> SqlParameterAssignment { get; private set; }
        }

        public class Mapper<T>
        {
            public IEnumerable<Mapping<T>> GetMappingElements()
            {
                foreach (var reflectionProperty in typeof(T).GetProperties())
                {
                    // Input parameters to the created assignment action
                    var accessor = Expression.Parameter(typeof(T), "input");
                    var sqlParmAccessor = Expression.Parameter(typeof(SqlParameter), "sqlParm");

                    // Access the property (compiled later, but use reflection to locate property)
                    var property = Expression.Property(accessor, reflectionProperty);

                    // Cast the property to ensure it is assignable to SqlProperty.Value 
                    // Should contain branching for DBNull.Value when property == null
                    var castPropertyToObject = Expression.Convert(property, typeof(object));


                    // The sql parameter
                    var sqlParm = new SqlParameter(reflectionProperty.Name, null);

                    // input parameter for assignment action
                    var sqlValueProp = Expression.Property(sqlParmAccessor, "Value");

                    // Expression assigning the retrieved property from input object 
                    // to the sql parameters 'Value' property
                    var dbnull = Expression.Constant(DBNull.Value);
                    var coalesce = Expression.Coalesce(castPropertyToObject, dbnull);
                    var assign = Expression.Assign(sqlValueProp, coalesce);

                    // Compile into action (removes reflection and makes real CLR object)
                    var assigner = Expression.Lambda<Action<T, SqlParameter>>(assign, accessor, sqlParmAccessor).Compile();

                    yield return
                        new Mapping<T>(reflectionProperty.Name, // Table name
                            sqlParm, // The constructed sql parameter
                            assigner); // The action assigning from the input <T> 

                }
            }
        }

        public static void Main(string[] args)
        {
            var sqlStuff = (new Mapper<Data>().GetMappingElements()).ToList();

            var sqlFieldsList = string.Join(", ", sqlStuff.Select(x => x.FieldName));
            var sqlValuesList = string.Join(", ", sqlStuff.Select(x => '@' + x.SqlParameter.ParameterName));

            var sqlStmt = string.Format("INSERT INTO test ({0}) VALUES ({1})", sqlFieldsList, sqlValuesList);

            var dataObjects = Enumerable.Range(1, 100).Select(id => new Data { Foo = 1.0 / id, ID = id, Title = null });

            var sw = Stopwatch.StartNew();

            using (SqlConnection cnn = new SqlConnection(@"server=.\sqlexpress;database=test;integrated security=SSPI"))
            {
                cnn.Open();

                SqlCommand cmd = new SqlCommand(sqlStmt, cnn);
                cmd.Parameters.AddRange(sqlStuff.Select(x => x.SqlParameter).ToArray());

                dataObjects.ToList()
                    .ForEach(dto =>
                        {
                            sqlStuff.ForEach(x => x.SqlParameterAssignment(dto, x.SqlParameter));
                            cmd.ExecuteNonQuery();
                        });
            }


            Console.WriteLine("Done in: " + sw.Elapsed);
        }
    }

    public class Data
    {
        public string Title { get; set; }
        public int ID { get; set; }
        public double Foo { get; set; }
    }
}

这篇关于替代反射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆