C#内置泛型委托:Func委托

🎯 365bet官网网 📅 2026-02-09 03:53:11 👤 admin 👀 9431 ❤️ 292
C#内置泛型委托:Func委托

1、什么是Func委托

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

2、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(T1 arg1, T2 arg2);

}

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

3、示例

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

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

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

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

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

代码示例如下:

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 fun1 = new Func(FunWithNoPara);

int result1= fun1();

Console.WriteLine(result1);

Console.WriteLine("----------------------------");

Func fun2 = delegate { return 19; };

int result2 = fun2();

Console.WriteLine(result2);

Console.WriteLine("----------------------------");

Func fun3 = () => { return 3; };

int result3 = fun3();

Console.WriteLine(result3);

Console.WriteLine("----------------------------");

//有一个参数,一个返回值

Func fun4 = new Func(FunWithPara);

int result4 = fun4(4);

Console.WriteLine($"这里是一个参数一个返回值的方法,返回值是:{result4}");

Console.WriteLine("----------------------------");

// 使用委托

Func fun5 = delegate (int i) { return i.ToString(); };

string result5 = fun5(5);

Console.WriteLine($"这里是一个参数一个返回值的委托,返回值是:{result5}");

Console.WriteLine("----------------------------");

// 使用匿名委托

Func fun6 = (int i) =>

{

return i.ToString();

};

string result6 = fun6(6);

Console.WriteLine($"这里是一个参数一个返回值的匿名委托,返回值是:{result6}");

Console.WriteLine("----------------------------");

// 多个输入参数

Func fun7 = new Func(FunWithMultiPara);

bool result7 = fun7(2, "2");

Console.WriteLine($"这里是有多个输入参数的方法,返回值是:{result7}");

Console.WriteLine("----------------------------");

// 使用委托

Func fun8 = delegate (int i, string s)

{

return i.ToString().Equals(s) ? true : false;

};

bool result8 = fun8(2, "abc");

Console.WriteLine($"这里是有多个输入参数的委托,返回值是:{result8}");

Console.WriteLine("----------------------------");

// 使用匿名委托

Func 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;

}

}

}

运行结果:

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(int id) where T : BaseModel;

List QueryAll() where T : BaseModel;

int Insert(T t) where T : BaseModel;

int Update(T t) where T : BaseModel;

int Delete(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(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) 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(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 list = this.ReaderToList(reader);

t = list.FirstOrDefault();

}

return t;

}

public List QueryAll() 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 list = new List();

using (SqlConnection conn = new SqlConnection(strConn))

{

SqlCommand command = new SqlCommand(sql, conn);

conn.Open();

SqlDataReader reader = command.ExecuteReader();

list = this.ReaderToList(reader);

}

return list;

}

public int Update(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 ReaderToList(SqlDataReader reader) where T : BaseModel

{

Type type = typeof(T);

List list = new List();

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(2);

Console.WriteLine($"姓名:{student.Name},年龄:{student.Age},Email地址:{student.Email}");

Console.WriteLine("----------------------------");

// 查询所有

List list = dal.QueryAll();

Console.WriteLine($"集合个数:{list.Count}");

Console.WriteLine("----------------------------");

// 插入

Student studentIns = new Student()

{

Name = "小明",

Age = 20,

Sex = 2,

Email = "xiaoming@qq.com"

};

bool resultIns = dal.Insert(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(studentUpd) > 0 ? true : false;

Console.WriteLine($"更新执行结果:{resultUpd}");

Console.WriteLine("----------------------------");

// 删除

bool resultDel = dal.Delete(3) > 0 ? true : false;

Console.WriteLine($"删除执行结果:{resultDel}");

#endregion

Console.ReadKey();

}

}

}

8、结果

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(int id) where T : BaseModel

{

Type type = typeof(T);

string sql = $"delete from {type.Name} where Id=@Id";

Func func = (SqlCommand command) =>

{

SqlParameter para = new SqlParameter("Id", id);

command.Parameters.Add(para);

return command.ExecuteNonQuery();

};

return ExcuteSql(sql, func);

}

public int Insert(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 func = (SqlCommand command) =>

{

command.Parameters.AddRange(parameters);

return command.ExecuteNonQuery();

};

result = ExcuteSql(strSQL, func);

return result;

}

public T Query(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 func = (SqlCommand command) =>

{

SqlParameter para = new SqlParameter("@Id", id);

command.Parameters.Add(para);

SqlDataAdapter adapter = new SqlDataAdapter(command);

//SqlDataReader reader = command.ExecuteReader();

//List list = this.ReaderToList(reader);

adapter.Fill(dt);

List list = ConvertToList(dt);

T tResult = list.FirstOrDefault();

return tResult;

};

t = ExcuteSql(sql, func);

return t;

}

public List QueryAll() 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> func = (SqlCommand command) =>

{

SqlDataReader reader = command.ExecuteReader();

List list = this.ReaderToList(reader);

return list;

};

return ExcuteSql>(sql, func);

}

public int Update(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 func = (SqlCommand command) =>

{

command.Parameters.AddRange(parameters);

return command.ExecuteNonQuery();

};

result = ExcuteSql(strSQL, func);

return result;

}

//多个方法里面重复对数据库的访问 想通过委托解耦,去掉重复代码

private T ExcuteSql(string sql, Func 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 ReaderToList(SqlDataReader reader) where T : BaseModel

{

Type type = typeof(T);

List list = new List();

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(2);

//Console.WriteLine($"姓名:{student.Name},年龄:{student.Age},Email地址:{student.Email}");

//Console.WriteLine("----------------------------");

//// 查询所有

//List list = dal.QueryAll();

//Console.WriteLine($"集合个数:{list.Count}");

//Console.WriteLine("----------------------------");

//// 插入

//Student studentIns = new Student()

//{

// Name = "小明",

// Age = 20,

// Sex = 2,

// Email = "xiaoming@qq.com"

//};

//bool resultIns = dal.Insert(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(studentUpd) > 1 ? true : false;

//Console.WriteLine($"更新执行结果:{resultUpd}");

//Console.WriteLine("----------------------------");

//// 删除

//bool resultDel = dal.Delete(5) > 1 ? true : false;

//Console.WriteLine($"删除执行结果:{resultDel}");

#endregion

#region 利用委托

// 查询

FunBaseDAL dal = new FunBaseDAL();

Student student = dal.Query(1);

Console.WriteLine($"姓名:{student.Name},年龄:{student.Age},Email地址:{student.Email}");

Console.WriteLine("----------------------------");

// 查询所有

List list = dal.QueryAll();

Console.WriteLine($"集合个数:{list.Count}");

Console.WriteLine("----------------------------");

// 插入

Student studentIns = new Student()

{

Name = "tom",

Age = 19,

Sex = 1,

Email = "tom@163.com"

};

bool resultIns = dal.Insert(studentIns) > 0 ? true : false;

Console.WriteLine($"插入执行结果:{resultIns}");

Console.WriteLine("----------------------------");

List list1 = dal.QueryAll();

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(studentUpd) > 0 ? true : false;

Console.WriteLine($"更新执行结果:{resultUpd}");

Console.WriteLine("----------------------------");

// 删除

bool resultDel = dal.Delete(8) > 0 ? true : false;

Console.WriteLine($"删除执行结果:{resultDel}");

List list2 = dal.QueryAll();

Console.WriteLine($"删除后集合个数:{list2.Count}");

Console.WriteLine("----------------------------");

#endregion

Console.ReadKey();

}

}

}

11、结果

注意

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

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

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

1、其实不用多次打开在开启,那样实现起来很麻烦。直接在连接字符串的后面加上MultipleActiveResultSets=true即可。 配置文件定义如下:

2、使用DataTable

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

///

/// 将DataTable转换成List

///

///

///

///

private List ConvertToList(DataTable dt) where T:BaseModel

{

Type type = typeof(T);

List list = new List();

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;

}

🎯 相关推荐

🎁 合作伙伴