简体   繁体   中英

using Generics in C#

I have started looking into using generics in C#. As an example what i have done is that I have an abstract class which implements generic methods. these generic methods take a sql query, a connection string and the Type T as parameters and then construct the data set, populate the object and return it back. This way each business object does not need to have a method to populate it with data or construct its data set. All we need to do is pass the type, the sql query and the connection string and these methods do the rest.I am providing the code sample here. I am just looking to discuss with people who might have a better solution to what i have done.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using MWTWorkUnitMgmtLib.Business;
using System.Collections.ObjectModel;
using System.Reflection;

namespace MWTWorkUnitMgmtLib.TableGateway
{
    public abstract class TableGateway
    {
        public TableGateway()
        {

        }

        protected abstract string GetConnection();
        protected abstract string GetTableName();

        public DataSet GetDataSetFromSql(string connectionString, string sql)
        {
            DataSet ds = null;
            using (SqlConnection connection = new SqlConnection(connectionString))
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = sql;
                connection.Open();
                using (ds = new DataSet())
                using (SqlDataAdapter adapter = new SqlDataAdapter(command))
                {
                    adapter.Fill(ds);
                }
            }
            return ds;
        }

        public static bool ContainsColumnName(DataRow dr, string columnName)
        {
            return dr.Table.Columns.Contains(columnName); 
        }

        public DataTable GetDataTable(string connString, string sql)
        {
            DataSet ds = GetDataSetFromSql(connString, sql);
            DataTable dt = null;
            if (ds != null)
            {
                if (ds.Tables.Count > 0)
                {
                    dt = ds.Tables[0];
                }
            }
            return dt; 
        }

        public T Construct<T>(DataRow dr, T t) where T : class, new()
        {
            Type t1 = t.GetType();
            PropertyInfo[] properties = t1.GetProperties();

            foreach (PropertyInfo property in properties)
            {
                if (ContainsColumnName(dr, property.Name) && (dr[property.Name] != null))
                    property.SetValue(t, dr[property.Name], null); 
            }

            return t; 
        }

        public T GetByID<T>(string connString, string sql, T t) where T : class, new()
        {
            DataTable dt = GetDataTable(connString, sql);
            DataRow dr = dt.Rows[0];
            return Construct(dr, t); 
        }

        public List<T> GetAll<T>(string connString, string sql, T t) where T : class, new()
        {
            List<T> collection = new List<T>();
            DataTable dt = GetDataTable(connString, sql);
            foreach (DataRow dr in dt.Rows)
                collection.Add(Construct(dr, t));

            return collection; 
        }
    }
}

You can improve perfs by generating and caching delegates to set properties:

public static class Utils
{
        public static Action<T, object> MethodDelegateFor<T>(MethodInfo method)
        {
            var parameter = method.GetParameters().Single();
            var instance = Expression.Parameter(typeof(T), "instance");
            var argument = Expression.Parameter(typeof(object), "argument");
            var methodCall = Expression.Call(
                instance,
                method,
                Expression.Convert(argument, parameter.ParameterType)
                );
            return Expression.Lambda<Action<T, object>>(
                methodCall,
                instance, argument
                ).Compile();
        }

        public static Action<T, object> PropertySetterFor<T>(PropertyInfo property)
        {
            return MethodDelegateFor<T>(property.GetSetMethod());
        }
}

usage:

var propSetter = Utils.PropertySetterFor<T>(yourPropInfo);
propSetter(newInstance, theValue);

It would be more powerful, I believe, to use the unit of work pattern, with the repository pattern, but modified to a generic example.

Then you could build a fully functioning CRUD, with Polymorphism for "special" things, you need your specializations to do.

Would also switch out the old SQL command with entity framework. would lighten your workload considerably.

That is what I would do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM