使用弱类型集合传输数据
当委托遇到协变和逆变
看看下面两个委托方法,哪个可以绑定到本文说的这个.NET方法:
bool SaveUsers(IList<IUserInfo> users){ }
Func<List<IUserInfo>,bool> fun;
Func<List<Object>,bool> fun2;
很明显,委托方法 fun2不能绑定,因为参数是 in 的,不是方法out的,所以调用的参数类型不能使用派生程度更小的类型;
再看看下面这种情况:
List<IUserInfo> GetUsers(string likeName){ }
Func<string,IEnumerable<IUserInfo>> fun;
Func<string,IEnumerable> fun2;
这里,fun,fun2都可以绑定到方法上,因为泛型方法的形参作为返回值,是out的,可以使用派生程度更小的类型。
这是不是很熟悉的泛型类型的 协变和逆变?
我们知道,反射的时候,利用委托绑定要反射的方法,能够大大提高方法的调用效率,所以对于我们的方法参数,如果调用的时候无法获知具体的类型,从而无法正确构造合适的委托方法,不如退而求其次,让被调用的方法参数采用弱类型方式,这样就可以构造对应的委托方法了。
因此,对我们.NET方法中的 SaveUsers 进行改造:
public bool SaveUsers(IList<IUserInfo> users)
{
UserDb.AddRange(users);
return true;
}
public IUserInfo CreateUserObject()
{
return EntityBuilder.CreateEntity<IUserInfo>();
}
public bool SaveUsers2(IEnumerable<Object> para)
{
var users = from u in para
select u as IUserInfo;
return SaveUsers (users.ToList());
}
这里增加一个方法 SaveUsers2,它采用IEnumerable<Object> ,而不是更为具体的 IList<IUserInfo>,那么采用下面的方式构造方法 SaveUsers2 对应的委托方法就可以了:
MethodInfo^ method = dotnetObject->GetType()->GetMethod("SaveUsers2", BindingFlags::Public | BindingFlags::Instance);
Func<System::Collections::Generic::IEnumerable<Object^>^,bool>^ fun2 =
(Func<System::Collections::Generic::IEnumerable<Object^>^, bool>^)Delegate::CreateDelegate(System::Func<Collections::Generic::IEnumerable<Object^>^, bool>::typeid,
this->dotnetObject, method);
这样要构造一个泛型List就不必像之前的方法那么麻烦了:
System::Collections::Generic::List<Object^>^ list = gcnew System::Collections::Generic::List<Object^>;
反射调用SaveUser2完整的代码如下:
//示例2:调用.NET弱类型的参数方法,以便通过委托方法调用
//构建委托方法比较容易,适用于参数数量多于1个的情况,
bool SaveUsers2(std::list<CppUserInfo> users)
{
MethodInfo^ method = dotnetObject->GetType()->GetMethod("SaveUsers2", BindingFlags::Public | BindingFlags::Instance);
Func<System::Collections::Generic::IEnumerable<Object^>^,bool>^ fun2 =
(Func<System::Collections::Generic::IEnumerable<Object^>^, bool>^)Delegate::CreateDelegate(System::Func<Collections::Generic::IEnumerable<Object^>^, bool>::typeid,
this->dotnetObject, method);
Object^ userObj = CreateUserObject();
System::Collections::Generic::List<Object^>^ list = gcnew System::Collections::Generic::List<Object^>;
for each (CppUserInfo user in users)
{
helper->CurrEntity = ((ICloneable^)userObj)->Clone();//使用克隆,避免每次反射
helper->SetPropertyValue("ID", user.ID);
helper->SetPropertyValue("Name", gcnew String(user.Name));
helper->SetPropertyValue("Birthday", Covert2NetDateTime(user.Birthday));
list->Add(helper->CurrEntity);
}
bool result = fun2(list);
return result;
}










