文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C#的Func委托怎么实现

2023-06-29 11:39

关注

本篇内容介绍了“C#的Func委托怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、什么是Func委托

Func委托代表有返回类型的委托

二、Func委托定义

查看Func的定义:

using System.Runtime.CompilerServices;namespace System{    //    // 摘要:    //     封装一个方法,该方法具有两个参数,并返回由 TResult 参数指定的类型的值。    //    // 参数:    //   arg1:    //     此委托封装的方法的第一个参数。    //    //   arg2:    //     此委托封装的方法的第二个参数。    //    // 类型参数:    //   T1:    //     此委托封装的方法的第一个参数的类型。    //    //   T2:    //     此委托封装的方法的第二个参数的类型。    //    //   TResult:    //     此委托封装的方法的返回值类型。    //    // 返回结果:    //     此委托封装的方法的返回值。    [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]    public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);}

你会发现,Func其实就是有多个输出参数并且有返回值的delegate。

3、示例

Func至少0个输入参数,至多16个输入参数,根据返回值泛型返回。必须有返回值,不可void。

Func<int> 表示没有输入参参,返回值为int类型的委托。

Func<object,string,int> 表示传入参数为object, string ,返回值为int类型的委托。

Func<object,string,int> 表示传入参数为object, string, 返回值为int类型的委托。

Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型),返回值为int类型的委托。

C#的Func委托怎么实现

代码示例如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunDemo{    class Program    {        static void Main(string[] args)        {            // 无参数,只要返回值             Func<int> fun1 = new Func<int>(FunWithNoPara);            int result1= fun1();            Console.WriteLine(result1);            Console.WriteLine("----------------------------");            Func<int> fun2 = delegate { return 19; };            int result2 = fun2();            Console.WriteLine(result2);            Console.WriteLine("----------------------------");            Func<int> fun3 = () => { return 3; };            int result3 = fun3();            Console.WriteLine(result3);            Console.WriteLine("----------------------------");            //有一个参数,一个返回值            Func<int, int> fun4 = new Func<int, int>(FunWithPara);            int result4 = fun4(4);            Console.WriteLine($"这里是一个参数一个返回值的方法,返回值是:{result4}");            Console.WriteLine("----------------------------");            // 使用委托            Func<int, string> fun5 = delegate (int i) { return i.ToString(); };            string result5 = fun5(5);            Console.WriteLine($"这里是一个参数一个返回值的委托,返回值是:{result5}");            Console.WriteLine("----------------------------");            // 使用匿名委托            Func<int, string> fun6 = (int i) =>             {                return i.ToString();            };            string result6 = fun6(6);            Console.WriteLine($"这里是一个参数一个返回值的匿名委托,返回值是:{result6}");            Console.WriteLine("----------------------------");            // 多个输入参数            Func<int, string, bool> fun7 = new Func<int, string, bool>(FunWithMultiPara);            bool result7 = fun7(2, "2");            Console.WriteLine($"这里是有多个输入参数的方法,返回值是:{result7}");            Console.WriteLine("----------------------------");            // 使用委托            Func<int, string, bool> fun8 = delegate (int i, string s)             {                return i.ToString().Equals(s) ? true : false;            };            bool result8 = fun8(2, "abc");            Console.WriteLine($"这里是有多个输入参数的委托,返回值是:{result8}");            Console.WriteLine("----------------------------");            // 使用匿名委托            Func<int, string, bool> fun9 = (int i, string s) =>             {                return i.ToString().Equals(s) ? true : false;            };            bool result9 = fun9(45, "ert");            Console.WriteLine($"这里是有多个输入参数的匿名委托,返回值是:{result9}");            Console.ReadKey();        }        static int FunWithNoPara()        {            return 10;        }        static int FunWithPara(int i)        {            return i;        }        static bool FunWithMultiPara(int i,string s)        {            return i.ToString().Equals(s) ? true : false;        }    }}

运行结果:

C#的Func委托怎么实现

4、真实示例

在下面的示例中,利用Func委托封装数据库通用访问类。

1、定义BaseModel基类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunApplication.Model{    public class BaseModel    {        public int Id { get; set; }    }}

2、定义Student类继承自BaseModel基类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunApplication.Model{    public class Student : BaseModel    {        public string Name { get; set; }        public int Age { get; set; }        public int Sex { get; set; }        public string Email { get; set; }    }}

3、定义数据库访问方法接口

using FunApplication.Model;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunApplication.IDAL{    public interface IBaseDAL    {        T Query<T>(int id) where T : BaseModel;        List<T> QueryAll<T>() where T : BaseModel;        int Insert<T>(T t) where T : BaseModel;        int Update<T>(T t) where T : BaseModel;        int Delete<T>(int id) where T : BaseModel;    }}

4、定义属性帮助类

using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks;namespace FunApplication.AttributeExtend{    public static class AttributeHelper    {        public static string GetColumnName(this PropertyInfo prop)        {            if (prop.IsDefined(typeof(ColumnAttribute), true))            {                ColumnAttribute attribute = (ColumnAttribute)prop.GetCustomAttribute(typeof(ColumnAttribute), true);                return attribute.GetColumnName();            }            else            {                return prop.Name;            }        }    }}

5、定义ColumnAttribute类

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunApplication.AttributeExtend{    [AttributeUsage(AttributeTargets.Property)]    public class ColumnAttribute : Attribute    {        public ColumnAttribute(string name)        {            this._Name = name;        }        private string _Name = null;        public string GetColumnName()        {            return this._Name;        }    }}

6、定义数据库方法接口实现类

using FunApplication.IDAL;using FunApplication.Model;using System;using System.Collections.Generic;using System.Configuration;using System.Data.SqlClient;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Reflection;using FunApplication.AttributeExtend;namespace FunApplication.DAL{    public  class BaseDAL : IBaseDAL    {        // 数据库链接字符串        private static string strConn = ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString;        public  int Delete<T>(int id) where T : BaseModel        {            int result = 0;            using (SqlConnection conn = new SqlConnection(strConn))            {                string strSQL = "delete from Student where Id=@Id";                SqlParameter para = new SqlParameter("Id", id);                SqlCommand command = new SqlCommand(strSQL, conn);                command.Parameters.Add(para);                conn.Open();                result = command.ExecuteNonQuery();            }            return result;        }        public int Insert<T>(T t) where T : BaseModel        {            int result = 0;            using (SqlConnection conn = new SqlConnection(strConn))            {                Type type = typeof(T);                var propArray = type.GetProperties().Where(p => p.Name != "Id");                string strSQL = "insert into Student Values (@Name,@Age,@Sex,@Email) ";                SqlCommand command = new SqlCommand(strSQL, conn);                var parameters = propArray.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();                command.Parameters.AddRange(parameters);                conn.Open();                result = command.ExecuteNonQuery();            }                return result;        }        public T Query<T>(int id) where T : BaseModel        {            Type type = typeof(T);            string columnString = string.Join(",", type.GetProperties().Select(p => $"[{p.GetColumnName()}]"));            string sql = $"SELECT {columnString} FROM [{type.Name}] WHERE Id={id}";            T t = null;// (T)Activator.CreateInstance(type);            using (SqlConnection conn = new SqlConnection(strConn))            {                SqlCommand command = new SqlCommand(sql, conn);                conn.Open();                SqlDataReader reader = command.ExecuteReader();                List<T> list = this.ReaderToList<T>(reader);                t = list.FirstOrDefault();                      }            return t;        }        public List<T> QueryAll<T>() where T : BaseModel        {            Type type = typeof(T);            string columnString = string.Join(",", type.GetProperties().Select(p => $"[{p.GetColumnName()}]"));            string sql = $"SELECT {columnString} FROM [{type.Name}] ";            List<T> list = new List<T>();            using (SqlConnection conn = new SqlConnection(strConn))            {                SqlCommand command = new SqlCommand(sql, conn);                conn.Open();                SqlDataReader reader = command.ExecuteReader();                list = this.ReaderToList<T>(reader);            }            return list;        }        public int Update<T>(T t) where T : BaseModel        {            int result = 0;            using (SqlConnection conn = new SqlConnection(strConn))            {                Type type = typeof(T);                var propArray = type.GetProperties().Where(p => p.Name != "Id");                string columnString = string.Join(",", propArray.Select(p => $"[{p.GetColumnName()}]=@{p.GetColumnName()}"));                var parameters = propArray.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();                                //必须参数化  否则引号?  或者值里面还有引号                string strSQL = $"UPDATE [{type.Name}] SET {columnString} WHERE Id={t.Id}";                SqlCommand command = new SqlCommand(strSQL, conn);                command.Parameters.AddRange(parameters);                conn.Open();                result = command.ExecuteNonQuery();                        }            return result;        }        private List<T> ReaderToList<T>(SqlDataReader reader) where T : BaseModel        {            Type type = typeof(T);            List<T> list = new List<T>();            while (reader.Read())//表示有数据  开始读            {                T t = (T)Activator.CreateInstance(type);                foreach (var prop in type.GetProperties())                {                    object oValue = reader[prop.GetColumnName()];                    if (oValue is DBNull)                        oValue = null;                    prop.SetValue(t, oValue);//除了guid和枚举                }                list.Add(t);            }            return list;        }    }}

7、在Main()方法中调用

using FunApplication.DAL;using FunApplication.Model;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunApplication{    class Program    {        static void Main(string[] args)        {            #region MyRegion            BaseDAL dal = new BaseDAL();            // 查询            Student student = dal.Query<Student>(2);            Console.WriteLine($"姓名:{student.Name},年龄:{student.Age},Email地址:{student.Email}");            Console.WriteLine("----------------------------");            // 查询所有            List<Student> list = dal.QueryAll<Student>();            Console.WriteLine($"集合个数:{list.Count}");            Console.WriteLine("----------------------------");            // 插入            Student studentIns = new Student()            {                Name = "小明",                Age = 20,                Sex = 2,                Email = "xiaoming@qq.com"            };            bool resultIns = dal.Insert<Student>(studentIns) > 0 ? true : false;            Console.WriteLine($"插入执行结果:{resultIns}");            Console.WriteLine("----------------------------");            // 更新            Student studentUpd = new Student()            {                Id = 1,                Name = "zhangsan1234",                Age = 20,                Sex = 2,                Email = "zhangsan1234@qq.com"            };            bool resultUpd = dal.Update<Student>(studentUpd) > 0 ? true : false;            Console.WriteLine($"更新执行结果:{resultUpd}");            Console.WriteLine("----------------------------");            // 删除            bool resultDel = dal.Delete<Student>(3) > 0 ? true : false;            Console.WriteLine($"删除执行结果:{resultDel}");            #endregion            Console.ReadKey();        }    }}

8、结果

C#的Func委托怎么实现

9、优化

仔细观察上面步骤7中的代码,你会发现在每个方法中都有重复的代码,打开链接,执行SqlCommand命令,那么这些重复的代码能不能提取到一个公共的方法中进行调用呢?答案是可以的,那就是利用Func委托,看下面优化后的代码:

using FunApplication.AttributeExtend;using FunApplication.IDAL;using FunApplication.Model;using System;using System.Collections.Generic;using System.Configuration;using System.Data;using System.Data.SqlClient;using System.Linq;using System.Reflection;using System.Text;using System.Threading.Tasks;namespace FunApplication.DAL{    public class FunBaseDAL : IBaseDAL    {        // 数据库链接字符串        private static string strConn = ConfigurationManager.ConnectionStrings["DbConnection"].ConnectionString;        public int Delete<T>(int id) where T : BaseModel        {            Type type = typeof(T);            string sql = $"delete from {type.Name} where Id=@Id";            Func<SqlCommand, int> func = (SqlCommand command) =>             {                               SqlParameter para = new SqlParameter("Id", id);                command.Parameters.Add(para);                return command.ExecuteNonQuery();            };            return ExcuteSql<int>(sql, func);        }        public int Insert<T>(T t) where T : BaseModel        {            int result = 0;            Type type = typeof(T);            var propArray = type.GetProperties().Where(p => p.Name != "Id");            string strSQL = "insert into Student Values (@Name,@Age,@Sex,@Email) ";            var parameters = propArray.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();            Func<SqlCommand, int> func = (SqlCommand command) =>             {                command.Parameters.AddRange(parameters);                return command.ExecuteNonQuery();            };            result = ExcuteSql<int>(strSQL, func);            return result;        }        public T Query<T>(int id) where T : BaseModel        {            Type type = typeof(T);            string columnString = string.Join(",", type.GetProperties().Select(p => $"[{p.GetColumnName()}]"));            string sql = $"SELECT {columnString} FROM [{type.Name}] WHERE Id=@Id";            T t = null;            DataTable dt = new DataTable();                        Func<SqlCommand, T> func = (SqlCommand command) =>             {                SqlParameter para = new SqlParameter("@Id", id);                command.Parameters.Add(para);                SqlDataAdapter adapter = new SqlDataAdapter(command);                //SqlDataReader reader = command.ExecuteReader();                //List<T> list = this.ReaderToList<T>(reader);                adapter.Fill(dt);                List<T> list = ConvertToList<T>(dt);                T tResult = list.FirstOrDefault();                return tResult;            };            t = ExcuteSql<T>(sql, func);            return t;        }        public List<T> QueryAll<T>() where T : BaseModel        {            Type type = typeof(T);            string columnString = string.Join(",", type.GetProperties().Select(p => $"[{p.GetColumnName()}]"));            string sql = $"SELECT {columnString} FROM [{type.Name}] ";            T t = null;            Func<SqlCommand, List<T>> func = (SqlCommand command) =>            {                SqlDataReader reader = command.ExecuteReader();                List<T> list = this.ReaderToList<T>(reader);                return list;            };            return ExcuteSql<List<T>>(sql, func);        }        public int Update<T>(T t) where T : BaseModel        {            int result = 0;            Type type = typeof(T);            var propArray = type.GetProperties().Where(p => p.Name != "Id");            string columnString = string.Join(",", propArray.Select(p => $"[{p.GetColumnName()}]=@{p.GetColumnName()}"));            var parameters = propArray.Select(p => new SqlParameter($"@{p.GetColumnName()}", p.GetValue(t) ?? DBNull.Value)).ToArray();            //必须参数化  否则引号?  或者值里面还有引号            string strSQL = $"UPDATE [{type.Name}] SET {columnString} WHERE Id={t.Id}";            Func<SqlCommand, int> func = (SqlCommand command) =>             {                command.Parameters.AddRange(parameters);                return command.ExecuteNonQuery();            };            result = ExcuteSql<int>(strSQL, func);            return result;        }        //多个方法里面重复对数据库的访问  想通过委托解耦,去掉重复代码        private T ExcuteSql<T>(string sql, Func<SqlCommand, T> func)        {            using (SqlConnection conn = new SqlConnection(strConn))            {                using (SqlCommand command = new SqlCommand(sql, conn))                {                    conn.Open();                    SqlTransaction sqlTransaction = conn.BeginTransaction();                    try                    {                        command.Transaction = sqlTransaction;                        T tResult = func.Invoke(command);                        sqlTransaction.Commit();                        return tResult;                    }                    catch (Exception ex)                    {                        sqlTransaction.Rollback();                        throw;                    }                }            }        }        private List<T> ReaderToList<T>(SqlDataReader reader) where T : BaseModel        {            Type type = typeof(T);            List<T> list = new List<T>();            while (reader.Read())//表示有数据  开始读            {                T t = (T)Activator.CreateInstance(type);                foreach (var prop in type.GetProperties())                {                    object oValue = reader[prop.GetColumnName()];                    if (oValue is DBNull)                        oValue = null;                    prop.SetValue(t, oValue);//除了guid和枚举                }                list.Add(t);            }            reader.Close();            return list;        }    }}

10、在Main()方法中调用

using FunApplication.DAL;using FunApplication.Model;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace FunApplication{    class Program    {        static void Main(string[] args)        {            #region 传统实现            //BaseDAL dal = new BaseDAL();            //// 查询            //Student student = dal.Query<Student>(2);            //Console.WriteLine($"姓名:{student.Name},年龄:{student.Age},Email地址:{student.Email}");            //Console.WriteLine("----------------------------");            //// 查询所有            //List<Student> list = dal.QueryAll<Student>();            //Console.WriteLine($"集合个数:{list.Count}");            //Console.WriteLine("----------------------------");            //// 插入            //Student studentIns = new Student()            //{            //    Name = "小明",            //    Age = 20,            //    Sex = 2,            //    Email = "xiaoming@qq.com"            //};            //bool resultIns = dal.Insert<Student>(studentIns) > 0 ? true : false;            //Console.WriteLine($"插入执行结果:{resultIns}");            //Console.WriteLine("----------------------------");            //// 更新            //Student studentUpd = new Student()            //{            //    Id = 1,            //    Name = "zhangsan1234",            //    Age = 20,            //    Sex = 2,            //    Email = "zhangsan1234@qq.com"            //};            //bool resultUpd = dal.Update<Student>(studentUpd) > 1 ? true : false;            //Console.WriteLine($"更新执行结果:{resultUpd}");            //Console.WriteLine("----------------------------");            //// 删除            //bool resultDel = dal.Delete<Student>(5) > 1 ? true : false;            //Console.WriteLine($"删除执行结果:{resultDel}");            #endregion            #region 利用委托            // 查询            FunBaseDAL dal = new FunBaseDAL();            Student student = dal.Query<Student>(1);            Console.WriteLine($"姓名:{student.Name},年龄:{student.Age},Email地址:{student.Email}");            Console.WriteLine("----------------------------");            // 查询所有            List<Student> list = dal.QueryAll<Student>();            Console.WriteLine($"集合个数:{list.Count}");            Console.WriteLine("----------------------------");            // 插入            Student studentIns = new Student()            {                Name = "tom",                Age = 19,                Sex = 1,                Email = "tom@163.com"            };            bool resultIns = dal.Insert<Student>(studentIns) > 0 ? true : false;            Console.WriteLine($"插入执行结果:{resultIns}");            Console.WriteLine("----------------------------");            List<Student> list1 = dal.QueryAll<Student>();            Console.WriteLine($"插入后集合个数:{list1.Count}");            Console.WriteLine("----------------------------");            // 更新            Student studentUpd = new Student()            {                Id = 2,                Name = "马六123",                Age = 20,                Sex = 2,                Email = "maliu1234@qq.com"            };            bool resultUpd = dal.Update<Student>(studentUpd) > 0 ? true : false;            Console.WriteLine($"更新执行结果:{resultUpd}");            Console.WriteLine("----------------------------");            // 删除            bool resultDel = dal.Delete<Student>(8) > 0 ? true : false;            Console.WriteLine($"删除执行结果:{resultDel}");            List<Student> list2 = dal.QueryAll<Student>();            Console.WriteLine($"删除后集合个数:{list2.Count}");            Console.WriteLine("----------------------------");            #endregion            Console.ReadKey();        }    }}

11、结果

C#的Func委托怎么实现

注意

在使用SqlDataReader的时候有时会报错:“已有打开的与此Command相关联的DataReader,必须先将它关闭”。

同时打开两个或循环多个sqldatareader会出现以上错误。因为用的是sqldatareader做数据库的数据读取,sqlconnection开启没有关闭。

一个SqlConnection只能执行一次事务,没用一次必须关闭然后再开启。上面我只用了一次没有关闭,直接开启所以会报错。解决方案有如下两种:

1、其实不用多次打开在开启,那样实现起来很麻烦。直接在连接字符串的后面加上MultipleActiveResultSets=true即可。 配置文件定义如下:
<?xml version="1.0" encoding="utf-8" ?><configuration>  <connectionStrings>    <!--<add name="DbConnection" connectionString="Server=.;Initial Catalog=MyDb;User ID=sa;Password=123456;MultipleActiveResultSets=True"/>-->    <!--配置文件里面添加MultipleActiveResultSets=True-->    <add name="DbConnection" connectionString="Server=.;Initial Catalog=MyDb;User ID=sa;Password=123456;MultipleActiveResultSets=True"/>  </connectionStrings>    <startup>         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />    </startup></configuration>
2、使用DataTable

在上面是使用的SqlDataReader读取数据,然后转换成List<T>,可以用DataTable代替SqlDataReader,这样就不会报错了,代码如下:

/// <summary>/// 将DataTable转换成List/// </summary>/// <typeparam name="T"></typeparam>/// <param name="dt"></param>/// <returns></returns>private List<T> ConvertToList<T>(DataTable dt) where T:BaseModel{      Type type = typeof(T);      List<T> list = new List<T>();      foreach(DataRow dr in dt.Rows)      {          T t = (T)Activator.CreateInstance(type);          foreach(PropertyInfo prop in type.GetProperties())          {               object value = dr[prop.GetColumnName()];               if(value is DBNull)               {                    value = null;               }               prop.SetValue(t, value);          }          list.Add(t);        }        return list;}

“C#的Func委托怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯