从通用模型中获取模型
本文关键字:模型 获取 | 更新日期: 2023-09-27 18:20:27
如果我有以下方法;
private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact)
因此,在这个方法中,我可以传入FileClient
或FileContact
模型。
两者都有一个称为Contact
的单一属性,它也是一个模型,还有一些其他在两者之间不常见的属性。
现在我想从传入的模型中获取Contact
模型。
Contact sourceContact = fileClientOrContact.Contact;
然而,由于这是一个泛型,它不知道TSource
中有一个Contact
对象。
我的限制是,我不能针对FileClient
或FileContact
放置接口。这两种型号我基本上都摸不着。
如何从TSource
获取Contact对象?我能以某种方式使用反射吗?
您可以传递一个函数来返回Contact。
例如:
private FileClient CopyFileClientModel(FileClient fileClient) {
return this.CopyFileClientModel(fileClient, c => c.Client);
}
private FileContact CopyFileClientModel(FileContact fileContact) {
return this.CopyFileClientModel(fileContact, c => c.Client);
}
private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact, Func<TSource, Contact> contactGetter) {
var contact = contactGetter(fileClientOrContact);
// Whatever else...
}
您可以使用Visitor模式来包装这两个类,并让这两个访问者类从公共接口继承。
本质上,您将创建一个具有FileClient
或FileContact
的重复方法/属性的新类,并在构造函数中传递该类的实例。所有方法和属性都链接到要存储的类实例中的实际方法和属性。您的两个访问者类都将具有Contact
属性,因此您可以告诉访问者类从公共接口继承。
如果使用.NET 4:,则可以使用动态
private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact)
(
dynamic d = fileClientOrContact;
// Now you reach the Contact property
var x = d.Contact;
)
最好确认typeof(TSoruce)
是FileClient
或FileContact
你可以做的另一件事是包装这两个类。请参阅Wikipedia 中的适配器设计模式
但也许Generics
不是你的解决方案。为什么不将Method重载与FileClient
和FileContact
一起使用呢。你的方法签名接受任何TSource,但当方法得到int,long,Person时,它是无效的,所以如果你可以将TSource
限制为你期望的类型,那么Generics
不是合适的解决方案。
请改用Method overload
。并保存那些"创造性解决方案"
如果您使用C#4.0,则可以使用动态
dyanmic obj = fileClientOrContact;
Contact sourceContact = obj.Contact;
不过,这并不理想!(可能导致运行时异常)
编辑
或者,我可能会为每种类型使用两个重载函数,每个函数为共享功能调用一个公共函数。
类似的东西?
if (fileClientorContact is FileContact)
return fileClientorContact as Contact;
else
return ((Client)fileClientorContact).Contact;
当然,这假定fileClientorContact中的"Contact"与您要返回的类型相同。或者,如果两种类型都定义了Contact
属性,如您在问题中所建议的,则可以使用以下方法:
var propInfo = fileClientorContact.GetType().GetProperty("Contact");
if (propInfo == null)
return false; // replace with something appropriate
return propInfo.GetValue(fileClientorClient, null, null, null) as Contact;
这大致来自记忆,但这个想法应该是有效的。
如果FileContact
和FileClient
没有共享具有.Contact
的祖先,并且您无法为其实现通用接口,并且您确实希望使用反射,那么您可以执行以下操作:
var sourceProp = typeof(TSource).GetProperty("Source");
Contact contact;
if(sourceProp != null)
{
contact = (Contact)sourceProp.getValue(fileClientOrContact, null)
}