从通用模型中获取模型

本文关键字:模型 获取 | 更新日期: 2023-09-27 18:20:27

如果我有以下方法;

private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact)

因此,在这个方法中,我可以传入FileClientFileContact模型。

两者都有一个称为Contact的单一属性,它也是一个模型,还有一些其他在两者之间不常见的属性。

现在我想从传入的模型中获取Contact模型。

Contact sourceContact = fileClientOrContact.Contact;

然而,由于这是一个泛型,它不知道TSource中有一个Contact对象。

我的限制是,我不能针对FileClientFileContact放置接口。这两种型号我基本上都摸不着。

如何从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模式来包装这两个类,并让这两个访问者类从公共接口继承。

本质上,您将创建一个具有FileClientFileContact的重复方法/属性的新类,并在构造函数中传递该类的实例。所有方法和属性都链接到要存储的类实例中的实际方法和属性。您的两个访问者类都将具有Contact属性,因此您可以告诉访问者类从公共接口继承。

如果使用.NET 4:,则可以使用动态

private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact)
(
    dynamic d = fileClientOrContact;
    // Now you reach the Contact property
    var x = d.Contact;
)

最好确认typeof(TSoruce)FileClientFileContact

你可以做的另一件事是包装这两个类。请参阅Wikipedia 中的适配器设计模式


但也许Generics不是你的解决方案。为什么不将Method重载与FileClientFileContact一起使用呢。你的方法签名接受任何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;

这大致来自记忆,但这个想法应该是有效的。

如果FileContactFileClient没有共享具有.Contact的祖先,并且您无法为其实现通用接口,并且您确实希望使用反射,那么您可以执行以下操作:

    var sourceProp = typeof(TSource).GetProperty("Source");
    Contact contact;
    if(sourceProp != null)
    {
        contact = (Contact)sourceProp.getValue(fileClientOrContact, null)
    }