文章中有一部分来自网上找的资料,这部分资料很重要,为了不忘却,笔记。
如果在做一个项目的时候,想让自己的程序更加灵活,更加好维护,那么反射是少不了的。因此文章中,我使用了反射。
整个文章解决的问题如下:
如果我有一个类,这个类不管是在别的DLL里面,还是在我当前工程中,我想要动态的调用他的方法,我该如何做?也许这样很简单,但是如果问题变动一点点,如果我想动态的调用这个类中我想要调用的方法,我该怎么做?
Attribute是特性的意思,它可以用来为我解决这个问题,首先我先自定义一个Attribute,这个Attribute是网上的资料。
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class AttachDataAttribute : Attribute
{
public AttachDataAttribute(object key, object value)
{
this.Key = key;
this.Value = value;
}
public object Key { get; private set; }
public object Value { get; private set; }
}
这里定义了一个名为AttachData的特性,这个特性可以被其他自定义的类所使用。
接下来是一个从网上抄下来的扩展类
public static class AttachDataExtensions
{
public static object GetAttachedData(
this ICustomAttributeProvider provider, object key)
{
var attributes = (AttachDataAttribute[])provider.GetCustomAttributes(
typeof(AttachDataAttribute), false);
return attributes.First(a => a.Key.Equals(key)).Value;
}
public static T GetAttachedData<T>(
this ICustomAttributeProvider provider, object key)
{
return (T)provider.GetAttachedData(key);
}
}
这个类做到了让所有的可以拥有特性的属性都可以有一个扩展方法,方法的作用是根据当前这个属性的AttachData特性的key获取这个AttachData特性的value。
接下来,我加了一个扩展方法
public static class MethodInfoExtensions
{
public static bool ContainsAttributeKey(this MethodInfo methodInfo, object AttributeKey)
{
AttachDataAttribute[] attributes = methodInfo.GetCustomAttributes(typeof(AttachDataAttribute), false) as AttachDataAttribute[];
if (attributes == null) return false;
AttachDataAttribute obj = attributes.First(a => a.Key.Equals(AttributeKey));
return obj != null;
}
}
让所有的MethodInfo对象都拥有一个方法,这个方法是用于判断MethodInfo对象的特性中是否有某个key值,当然这个方法只能适用于使用了AttachData特性的方法。
然后,我有了一个自定义的类
[AttachData(typeof(int), "t")]
public class test
{
[AttachData(typeof(int),"t")]
public string a()
{
return "a";
}
[AttachData(typeof(int), "t")]
public string b()
{
return "b";
}
}
这个类中的两个方法都有AttachData特性,而这两个方法也就是我想要调用的方法。
使用反射,当我拥有了test的Type之后,通过Type我有了test的一个对象
Type type = assembly.GetType("atest.test");
object obj = type.GetConstructor(new Type[] { }).Invoke(new object[] { });
我有了方法的集合,并且根据集合我获得了我想要的这两个方法
MethodInfo[] m = type.GetMethods();
List<MethodInfo> ms = m.ToList().FindAll(s => s.IsDefined(typeof(AttachDataAttribute), false));
List<MethodInfo> m1 = ms.FindAll(s => s.ContainsAttributeKey(typeof(int)));
现在就可以执行网上都在说的invoke了,但是我觉得还差了点东西,如果我千辛万苦获得的两个函数就只能如此被invoke了,那我何必这样辛苦绕着写?
我获得了两个函数,但是我想用这两个函数,每个函数建立一个线程,在线程中来执行。
我定义了一个类,随便写的,只是为了实验
class aobject
{
public MethodInfo m;
public object obj;
}
然后我建立了线程
foreach (MethodInfo m2 in m1)
{
aobject ao = new aobject();
ao.m = m2;
ao.obj = obj;
Thread thread = new Thread(new ParameterizedThreadStart(a));
thread.Start(ao);
}
线程的回调函数如下
void a(object minfo)
{
aobject ao = minfo as aobject;
string re = ao.m.Invoke(ao.obj, new object[] { }).ToString();
Console.WriteLine(ao.m.Name + ":" + re);
}
我的想法是:
将MethodInfo当做参数传入线程回调函数中,然后再回调中使用while来执行,只要控制好了信号灯,那么就相当于是个成功的线程函数了。
至此,总结一下:
我有了AttachData特性,这个特性可以定义一个key和一个value。
我写上了AttachDataExtensions,但是文章中并未使用到他,那是因为这两个个扩展方法很好用,怕忘记了,虽然我这里用不到。
我定义了MethodInfoExtensions,它的扩展函数可以判断某个methodinfo是否被定义了AttachData特性,并且是否含有我需要的某个key。
我通过反射获取了自定义类atest的Type,并且获取了atest的methodinfo的集合,并且从这个集合中获取了含有AttachData特性,并且AttachData的key为Typeof(int)的方法。
我使用我获得的两个方法建立了两个线程。