zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C#泛型和反射实例解析

2023-06-13 09:15:41 时间

C#中的泛型和反射经常是一起工作的,因此这里就一次性的加以介绍了。

由于c#是强类型语言,一般来说函数的返回类型和参数的类型都是一早写好的,这也就造成了很多时候不像js那样方便使用,不够灵话。

因此就有了这个泛型,它可以让你的函数和参数在调用的时候才决定类型。如下例所示:

publicTabc<T>(Tword)
{
returnword;
returndefault(T);//关键字default可以对引用类型返回nullAble,int类型返回0,初始化一个T的感觉啦
}

abc<string>("x");

//struct是值类型
//好处调用的是如果参数是值类型可以不用著名test(100)而不需要test<int>(100);
publicvoidtest<T>(Tnumber)whereT:struct
{
intz=Convert.ToInt32(number);
//调用test(100);
}
//下面的不知道好处在哪用在什么地方,
publicvoidtest2<T>(Tlei)whereT:class
{
}
publicvoidtest3<T>()whereT:stooges
{
}
publicTtest4<T>()whereT:new()
{
Tabc=newT();
returnabc;
}
publicclassstooges
{
}

加了where我就不清楚在什么地方用的上了,这个以后再研究

反射能让我们的代码运行时动态的获取一些对象或者类的属性值等等,甚至是调用它们。

先来一个常用到的,我们想获取一个对象的全部属性和值,用js是:

for(varattrinobject){object[attr]=value,attr=attr}
varobj=newabc();
TypeT=typeof(abc);//typeof(Class)而不是typeof(object)哦
TypeV=obj.GetType();//obj.GetType()就是typeof(object的class)
PropertyInfo[]attrs=obj.GetType().GetProperties(BindingFlags.Instance|BindingFlags.Public);//获取attrs
foreach(PropertyInfoattrinattrs)
{
stringkey=attr.Name;//获取attrname
objectvalue=attr.GetValue(obj,null);//获取value
Typetype=attr.PropertyType;//类型
}

关键就是那个Type,获取Type后就可以做很多了

C#常用的方法为:

T.GetProperty("key").GetValue(obj,null);//readakeyvalue
T.GetProperty("key").SetValue(obj,"",null);//writeavaluetokey
//注意如果是字典
T.GetProperty("Item").GetValue(obj,new[]{"id"});//先拿Item然后才通过new[]{这里放指定的key}

再来看看更详细的

classMyClass
{
publicintx{get;set;}
publicinty{get;set;}
publicMyClass(inti)
{
x=y+i;
}
publicMyClass(inti,intj)
{
x=i;
y=j;
}
publicintsum()
{
returnx+y;
}
}

我们想获取这个Class的构造函数:

Typet=typeof(MyClass);
ConstructorInfo[]constructors=t.GetConstructors();//使用这个方法获取构造函数列表
for(inti=0;i<constructors.Length;i++)
{
ConstructorInfoconstructor=constructors[i];
//构造函数也是方法所以有GetParameters
ParameterInfo[]parameters=constructor.GetParameters();//获取当前构造函数的参数列表
stringparaTypeName=parameters[0].ParameterType.Name;//方法的参数类型名称
stringparaName=parameters[0].Name;//方法的参数名
}
//调用构造函数
object[]args=newobject[2];
args[0]=10;
args[1]=20;
//不用new直接实例化
objectinstance=constructors[0].Invoke(args);//实例化一个这个构造函数有两个参数的类型对象,如果参数为空,则为null
objectinstance=(t)Activator.CreateInstance(t);还有这种实例的方法,不清楚可以放参数没有

调用方法如下:

MethodInfo[]methods=T.GetMethods(BindingFlags.Public|BindingFlags.DeclaredOnly|BindingFlags.Instance);
foreach(MethodInfomethodinmethods)
{
stringreturn_name=method.ReturnType.Name;//返回方法的返回类型
stringname=method.Name;
if(name.Equals("sum",StringComparison.Ordinal))//指定方法名调用
{
intvalue=(int)method.Invoke(instance,null);//instance是之前实例好的对象,方法就是在这个对象之中
}
}

下面是一些参考代码:

Typet=typeof(MyClass);
Console.WriteLine("----------------Method------------------");
MethodInfo[]methods=t.GetMethods();
foreach(MethodInfomethodinmethods)
{
Console.WriteLine("Method:"+method);
//Console.WriteLine(method);
//Console.WriteLine("返回值:"+method.ReturnParameter);
}
Console.WriteLine("---------------Field-------------------");//字段,比如这种privatestaticstringname;
FieldInfo[]fields=t.GetFields(BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static);
foreach(FieldInfofieldinfields)
{
Console.WriteLine("Field:"+field);
}
Console.WriteLine("--------------Member--------------------");//成员即方法和属性
MemberInfo[]members=t.GetMembers();
foreach(MemberInfomemberinmembers)
{
Console.WriteLine("Member:"+member);
}
Console.WriteLine("--------------Property--------------------");//属性
PropertyInfo[]properties=t.GetProperties();
foreach(PropertyInfopropertyinproperties)
{
Console.WriteLine("Property:"+property);
}
Console.WriteLine("--------------Constructor--------------------");//构造函数
ConstructorInfo[]constructors=t.GetConstructors(BindingFlags.NonPublic|BindingFlags.Instance);
foreach(ConstructorInfoconstructorinconstructors)
{
Console.WriteLine("Constructor:"+constructor);
}

调用不用记太清楚,关键知道什么东西可以用反射获取和调用就可以了。

比较常使用的地方是用泛型写方法的时候,比如我们的泛型是一个不确定的类,然后我们要获取attr值等等的,就很好可以使用反射了。

还有通过string来调用方法,这个在js很长用到,比如obj["methodName"]();这里也可以用到反射来实现。

此外还需要注意:反射的性能是很慢的,也可以说动态就是慢,这个是很正常的,反射的性能优化可以参考使用动态编程之类的,不过这里就不提了。