C# 表達(dá)式目錄樹(shù)Expression的實(shí)現(xiàn)
表達(dá)式目錄樹(shù)
表達(dá)式目錄樹(shù):語(yǔ)法樹(shù),或者說(shuō)是一種數(shù)據(jù)結(jié)構(gòu)
1.表達(dá)式目錄樹(shù)Expression:System.Linq.Expressions;
2.描述了多個(gè)變量或者和常量之間的關(guān)系,按照一定的規(guī)則進(jìn)行組裝!
- 可以向委托一樣使用lambd表達(dá)式快捷聲明;
- 不能有語(yǔ)句體,聲明只能有一行代碼;
- 可以通過(guò)Compile(),編譯成一個(gè)委托;
Func<int, int, int> func = (m, n) =>
{
int i = 0;
return m * n + 2;
}; //委托 拉姆達(dá)表達(dá)式其實(shí)是作為委托的一個(gè)參數(shù),本質(zhì)是一個(gè)方法(匿名方法)
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2; //數(shù)據(jù)結(jié)構(gòu)--就像對(duì)一個(gè)計(jì)算做了一個(gè)精確的描述,展開(kāi)之后發(fā)現(xiàn),分為左邊,右邊,每個(gè)元素都可以把值都獲取出來(lái),二叉樹(shù)
var erpPlu= exp.Compile();//表達(dá)式目錄樹(shù)可以通過(guò)compile 轉(zhuǎn)換成一個(gè)委托
//表達(dá)式目錄樹(shù):語(yǔ)法樹(shù),或者說(shuō)是一種數(shù)據(jù)結(jié)構(gòu)
int iResult1 = func.Invoke(12, 23);
int iResult2 = exp.Compile().Invoke(12, 23);


表達(dá)式目錄樹(shù)的拼裝
手動(dòng)拼裝表達(dá)式目錄樹(shù),不是用的lambda的快捷方式
//表達(dá)式目錄樹(shù)的拼裝 Expression<Func<int>> expression = () => 123 + 234; //兩個(gè)常量相加-----表達(dá)式目錄樹(shù)的快捷聲明 Expression constant123 = Expression.Constant(123); Expression constant234 = Expression.Constant(234); Expression expressionAdd = Expression.Add(constant123, constant234); var exp = Expression.Lambda<Func<int>>(expressionAdd); var func = exp.Compile(); int iResult = func.Invoke();
Expression<Func<int, int, int>> exp = (m, n) => m * n + m + n + 2; //快捷聲明--其實(shí)編譯器提供的便捷功能---語(yǔ)法糖--具體實(shí)現(xiàn)可通過(guò)反編譯工具查看
//具體實(shí)現(xiàn)可通過(guò)反編譯工具查看
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m");
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int), "n");
Expression expContant2 = Expression.Constant(2, typeof(int));
Expression multipley = Expression.Multiply(parameterExpression, parameterExpression2);
Expression expAdd = Expression.Add(multipley, parameterExpression);
Expression expAdd1 = Expression.Add(expAdd, parameterExpression2);
Expression expAdd2 = Expression.Add(expAdd1, expContant2);
Expression<Func<int, int, int>> expression = Expression.Lambda<Func<int, int, int>>(expAdd2, new ParameterExpression[]
{
parameterExpression,
parameterExpression2
});
Func<int, int, int> fun = expression.Compile();
int iResult = fun.Invoke(10, 11);
var peopleQuery = new List<People>().AsQueryable();
Expression<Func<People, bool>> lambda = x => x.Id.ToString().Equals("5");
peopleQuery.Where(lambda);
ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "x");
FieldInfo idfield = typeof(People).GetField("Id");
var idExp = Expression.Field(parameterExpression, idfield);
MethodInfo toString = typeof(int).GetMethod("ToString", new Type[0]);
var toStringExp = Expression.Call(idExp, toString, Array.Empty<Expression>());
var Equals = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
Expression expressionConstant5 = Expression.Constant("5", typeof(string));
var equalsExp = Expression.Call(toStringExp, Equals, new Expression[]
{
expressionConstant5
});
Expression<Func<People, bool>> expression = Expression.Lambda<Func<People, bool>>(equalsExp, new ParameterExpression[]
{
parameterExpression
});
Func<People, bool> func = expression.Compile();
var bResult = func.Invoke(new People()
{
Id = 5,
Name = "海貝"
});
new List<People>().AsQueryable().Where(expression);
應(yīng)用
Linq to SQL
var dbSet = new List<People>().AsQueryable();//EF DbSet
dbSet.Where(p => p.Age == 25 & p.Name.Contains("陽(yáng)光下的微笑"));
Expression<Func<People, bool>> exp = null;
Console.WriteLine("用戶(hù)輸入個(gè)名稱(chēng),為空就跳過(guò)");
string name = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(name))
{
exp = p => p.Name.Contains(name);
}
Console.WriteLine("用戶(hù)輸入個(gè)最小年紀(jì),為空就跳過(guò)");
string age = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(age) && int.TryParse(age, out int iAge))
{
exp = p => p.Age > iAge;
}
上面的玩法是不是只有最后一個(gè)條件才生效?如果需要多個(gè)條件都滿足;怎么辦? 當(dāng)然是拼裝啊;
拼裝可以從最小粒度來(lái)組裝表達(dá)式目錄樹(shù);如果有一個(gè)封裝,你把各種條件給我,我從最小粒度開(kāi)始一個(gè)一個(gè)的拼裝起來(lái),不就是一個(gè)長(zhǎng)的表達(dá)式目錄樹(shù)了嗎?
解決方案:
調(diào)用方可以組裝一個(gè)很長(zhǎng)的表達(dá)式目錄樹(shù)傳遞過(guò)來(lái);
表達(dá)式目錄樹(shù)傳遞過(guò)來(lái)以后,在這里應(yīng)該做什么?應(yīng)該解析;
所有信息都在表達(dá)式目錄樹(shù)里面,自然也可以把他解析(找出來(lái))
解析就可以通過(guò)ExpressionVisitor解析----生成對(duì)應(yīng)的Sql語(yǔ)句;
ExpressionVisitor
表達(dá)式目錄樹(shù)的訪問(wèn)者----訪問(wèn)者模式;
1.Visit方法–訪問(wèn)表達(dá)式目錄樹(shù)的入口—分辨是什么類(lèi)型的表達(dá)式目錄
2.調(diào)度到更加專(zhuān)業(yè)的方法中進(jìn)一步訪問(wèn),訪問(wèn)一遍之后,生成一個(gè)新的表達(dá)式目錄 —有點(diǎn)像遞歸,不全是遞歸;
3.因?yàn)楸磉_(dá)式目錄樹(shù)是個(gè)二叉樹(shù),ExpressionVisitor一直往下訪問(wèn),一直到葉節(jié)點(diǎn);那就訪問(wèn)了所有的節(jié)點(diǎn);
4.在訪問(wèn)的任何一個(gè)環(huán)節(jié),都可以拿到對(duì)應(yīng)當(dāng)前環(huán)節(jié)的內(nèi)容(參數(shù)名稱(chēng)、參數(shù)值。。),就可以進(jìn)一步擴(kuò)展;
為什么要使用表達(dá)式目錄樹(shù)來(lái)拼裝解析呢:
1.可以提高重用性;
2.如果封裝好一個(gè)方法,接受一個(gè)表達(dá)式目錄樹(shù),在解析的時(shí)候,其實(shí)就是不斷的訪問(wèn),訪問(wèn)有規(guī)則;
3.任何一個(gè)表達(dá)式目錄樹(shù)都可以調(diào)用當(dāng)前方法來(lái)解析;
4.表達(dá)式目錄樹(shù)可以支持泛型;
{
Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Id > 5
&& x.Name.StartsWith("1") // like '1%'
&& x.Name.EndsWith("1") // like '%1'
&& x.Name.Contains("1");// like '%1%'
//string sql = string.Format("Delete From [{0}] WHERE [Age]>5 AND [ID] >5"
, typeof(People).Name
, " [Age]>5 AND [ID] >5" );
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
Console.WriteLine(vistor.Condition());
}
{
// ((( [Age] > '5') AND( [Name] = [name] )) OR( [Id] > '5' ))
string name = "AAA";
Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Name == name || x.Id > 5;
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
Console.WriteLine(vistor.Condition());
}
{
Expression<Func<People, bool>> lambda = x => x.Age > 5 || (x.Name == "A" && x.Id > 5);
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
Console.WriteLine(vistor.Condition());
}
{
Expression<Func<People, bool>> lambda = x => (x.Age > 5 || x.Name == "A") && x.Id > 5;
ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
vistor.Visit(lambda);
Console.WriteLine(vistor.Condition());
}
自己封裝的解析器,這就是EF6的底層原理,根據(jù)表達(dá)式樹(shù)自動(dòng)生成相應(yīng)的sql語(yǔ)句。
public class ConditionBuilderVisitor : ExpressionVisitor
{
private Stack<string> _StringStack = new Stack<string>();
public string Condition()
{
string condition = string.Concat(this._StringStack.ToArray());
this._StringStack.Clear();
return condition;
}
/// <summary>
/// 如果是二元表達(dá)式
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitBinary(BinaryExpression node)
{
if (node == null) throw new ArgumentNullException("BinaryExpression");
this._StringStack.Push(")");
base.Visit(node.Right);//解析右邊
this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");
base.Visit(node.Left);//解析左邊
this._StringStack.Push("(");
return node;
}
/// <summary>
/// 解析屬性
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitMember(MemberExpression node)
{
if (node == null) throw new ArgumentNullException("MemberExpression");
//this._StringStack.Push(" [" + node.Member.Name + "] ");
return node;
if (node.Expression is ConstantExpression)
{
var value1 = this.InvokeValue(node);
var value2 = this.ReflectionValue(node);
//this.ConditionStack.Push($"'{value1}'");
this._StringStack.Push("'" + value2 + "'");
}
else
{
this._StringStack.Push(" [" + node.Member.Name + "] ");
}
return node;
}
private object InvokeValue(MemberExpression member)
{
var objExp = Expression.Convert(member, typeof(object));//struct需要
return Expression.Lambda<Func<object>>(objExp).Compile().Invoke();
}
private object ReflectionValue(MemberExpression member)
{
var obj = (member.Expression as ConstantExpression).Value;
return (member.Member as FieldInfo).GetValue(obj);
}
/// <summary>
/// 常量表達(dá)式
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitConstant(ConstantExpression node)
{
if (node == null) throw new ArgumentNullException("ConstantExpression");
this._StringStack.Push(" '" + node.Value + "' ");
return node;
}
/// <summary>
/// 方法表達(dá)式
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
protected override Expression VisitMethodCall(MethodCallExpression m)
{
if (m == null) throw new ArgumentNullException("MethodCallExpression");
string format;
switch (m.Method.Name)
{
case "StartsWith":
format = "({0} LIKE {1}+'%')";
break;
case "Contains":
format = "({0} LIKE '%'+{1}+'%')";
break;
case "EndsWith":
format = "({0} LIKE '%'+{1})";
break;
default:
throw new NotSupportedException(m.NodeType + " is not supported!");
}
this.Visit(m.Object);
this.Visit(m.Arguments[0]);
string right = this._StringStack.Pop();
string left = this._StringStack.Pop();
this._StringStack.Push(String.Format(format, left, right));
return m;
}
}
internal static class SqlOperator
{
internal static string ToSqlOperator(this ExpressionType type)
{
switch (type)
{
case (ExpressionType.AndAlso):
case (ExpressionType.And):
return "AND";
case (ExpressionType.OrElse):
case (ExpressionType.Or):
return "OR";
case (ExpressionType.Not):
return "NOT";
case (ExpressionType.NotEqual):
return "<>";
case ExpressionType.GreaterThan:
return ">";
case ExpressionType.GreaterThanOrEqual:
return ">=";
case ExpressionType.LessThan:
return "<";
case ExpressionType.LessThanOrEqual:
return "<=";
case (ExpressionType.Equal):
return "=";
default:
throw new Exception("不支持該方法");
}
}
}
表達(dá)式目錄擴(kuò)展
表達(dá)式目錄樹(shù)動(dòng)態(tài)拼接的實(shí)現(xiàn)方式:
/// <summary>
/// 合并表達(dá)式 And Or Not擴(kuò)展
/// </summary>
public static class ExpressionExtend
{
/// <summary>
/// 合并表達(dá)式 expr1 AND expr2
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expr1"></param>
/// <param name="expr2"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
//return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters); 錯(cuò)誤的寫(xiě)法,兩個(gè)表達(dá)式不是同一個(gè)參數(shù)
//將兩個(gè)表達(dá)式的參數(shù)統(tǒng)一為參數(shù)c
ParameterExpression newParameter = Expression.Parameter(typeof(T), "c");
NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
var left = visitor.Replace(expr1.Body);
var right = visitor.Replace(expr2.Body); //為了能夠生成一個(gè)新的表達(dá)式目錄樹(shù)
var body = Expression.And(left, right);
return Expression.Lambda<Func<T, bool>>(body, newParameter);
}
/// <summary>
/// 合并表達(dá)式 expr1 or expr2
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expr1"></param>
/// <param name="expr2"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
ParameterExpression newParameter = Expression.Parameter(typeof(T), "c");
NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
var left = visitor.Replace(expr1.Body);
var right = visitor.Replace(expr2.Body);
var body = Expression.Or(left, right);
return Expression.Lambda<Func<T, bool>>(body, newParameter);
}
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
{
var candidateExpr = expr.Parameters[0];
var body = Expression.Not(expr.Body);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
}
/// <summary>
/// 建立新表達(dá)式
/// </summary>
internal class NewExpressionVisitor : ExpressionVisitor
{
public ParameterExpression _NewParameter { get; private set; }
public NewExpressionVisitor(ParameterExpression param)
{
this._NewParameter = param;
}
public Expression Replace(Expression exp)
{
return this.Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return this._NewParameter;
}
}
調(diào)用方如下:
{
Expression<Func<People, bool>> lambda1 = x => x.Age > 5;
Expression<Func<People, bool>> lambda2 = x => x.Id > 5;
//Expression<Func<People, bool>> newExpress = x => x.Age > 5 && x.Id > 5;
Expression<Func<People, bool>> lambda3 = lambda1.And(lambda2); //且
Expression<Func<People, bool>> lambda4 = lambda1.Or(lambda2);//或
Expression<Func<People, bool>> lambda5 = lambda1.Not();//非
Do1(lambda3);
Do1(lambda4);
Do1(lambda5);
}
private static void Do1(Expression<Func<People, bool>> func)
{
List<People> people = new List<People>()
{
new People(){Id=4,Name="123",Age=4},
new People(){Id=5,Name="234",Age=5},
new People(){Id=6,Name="345",Age=6},
};
List<People> peopleList = people.Where(func.Compile()).ToList();
}
對(duì)象深拷貝
硬編碼
PeopleCopy peopleCopy = new PeopleCopy()
{
Id = people.Id,
Name = people.Name,
Age = people.Age
};
通過(guò)反射實(shí)現(xiàn)
public class ReflectionMapper
{
/// <summary>
/// 反射
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
/// <param name="tIn"></param>
/// <returns></returns>
public static TOut Trans<TIn, TOut>(TIn tIn)
{
TOut tOut = Activator.CreateInstance<TOut>();
foreach (var itemOut in tOut.GetType().GetProperties())
{
var propIn = tIn.GetType().GetProperty(itemOut.Name);
itemOut.SetValue(tOut, propIn.GetValue(tIn));
}
foreach (var itemOut in tOut.GetType().GetFields())
{
var fieldIn = tIn.GetType().GetField(itemOut.Name);
itemOut.SetValue(tOut, fieldIn.GetValue(tIn));
}
return tOut;
}
}
通過(guò)序列化實(shí)現(xiàn)
/// <summary>
/// 使用第三方序列化反序列化工具
/// 還有automapper
/// </summary>
public class SerializeMapper
{
/// <summary>
/// 序列化反序列化方式
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
public static TOut Trans<TIn, TOut>(TIn tIn)
{
return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));
}
}
反射和序列化兩種實(shí)現(xiàn)方式性能不太好;
通過(guò)表達(dá)式目錄樹(shù)實(shí)現(xiàn)
通過(guò)表達(dá)式目錄樹(shù)動(dòng)態(tài)的生成硬編碼
Func<People, PeopleCopy> func = p => new PeopleCopy()
{
Id = p.Id,
Name = p.Name,
Age = p.Age
};
PeopleCopy peopleCopy3 = func.Invoke(people);
方法一:普通緩存
/// <summary>
/// 生成表達(dá)式目錄樹(shù) 緩存
/// </summary>
public class ExpressionMapper
{
/// <summary>
/// 字典緩存--hash分布
/// </summary>
private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
/// <summary>
/// 字典緩存表達(dá)式樹(shù)
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
/// <param name="tIn"></param>
/// <returns></returns>
public static TOut Trans<TIn, TOut>(TIn tIn)
{
string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
if (!_Dic.ContainsKey(key))
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
List<MemberBinding> memberBindingList = new List<MemberBinding>();
foreach (var item in typeof(TOut).GetProperties())
{
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
foreach (var item in typeof(TOut).GetFields())
{
MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
});
Func<TIn, TOut> func = lambda.Compile();//拼裝是一次性的
_Dic[key] = func;
}
return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
}
}
方法二:泛型緩存,性能較高
/// <summary>
/// 生成表達(dá)式目錄樹(shù) 泛型緩存
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
public class ExpressionGenericMapper<TIn, TOut>//Mapper`2
{
private static Func<TIn, TOut> _FUNC = null;
static ExpressionGenericMapper()
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
List<MemberBinding> memberBindingList = new List<MemberBinding>();
foreach (var item in typeof(TOut).GetProperties())
{
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
foreach (var item in typeof(TOut).GetFields())
{
MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
});
_FUNC = lambda.Compile();//拼裝是一次性的
}
public static TOut Trans(TIn t)
{
return _FUNC(t);
}
}
到此這篇關(guān)于C# 表達(dá)式目錄樹(shù)Expression的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C# 表達(dá)式目錄樹(shù)Expression內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# MJPEG 客戶(hù)端簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要介紹了C# MJPEG 客戶(hù)端簡(jiǎn)單實(shí)現(xiàn)的方法,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03
c# 從IE瀏覽器獲取當(dāng)前頁(yè)面的內(nèi)容
從IE瀏覽器獲取當(dāng)前頁(yè)面內(nèi)容可能有多種方式,今天我所介紹的是其中一種方法?;驹恚寒?dāng)鼠標(biāo)點(diǎn)擊當(dāng)前IE頁(yè)面時(shí),獲取鼠標(biāo)的坐標(biāo)位置,根據(jù)鼠標(biāo)位置獲取當(dāng)前頁(yè)面的句柄,然后根據(jù)句柄,調(diào)用win32的東西進(jìn)而獲取頁(yè)面內(nèi)容。感興趣的朋友可以參考下本文2021-06-06
winform實(shí)現(xiàn)關(guān)閉按鈕失效的兩種方法
這篇文章主要介紹了winform實(shí)現(xiàn)關(guān)閉按鈕失效的兩種方法,實(shí)例分析了WinForm實(shí)現(xiàn)關(guān)閉按鈕失效的原理與所涉及的相關(guān)技巧,需要的朋友可以參考下2015-09-09
C#利用PrintDocument定制打印單據(jù)的小例子
這篇文章主要給大家介紹了關(guān)于C#利用PrintDocument定制打印單據(jù)的小例子,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
C#實(shí)現(xiàn)身份證實(shí)名認(rèn)證接口的示例代碼
身份證實(shí)名認(rèn)證,即通過(guò)姓名和身份證號(hào)校驗(yàn)個(gè)人信息的匹配程度,廣泛應(yīng)用于金融、互聯(lián)網(wǎng)等多個(gè)領(lǐng)域,本文主要介紹了C#實(shí)現(xiàn)身份證實(shí)名認(rèn)證接口的示例代碼,感興趣的可以了解一下2024-09-09

