从通用模型中获取模型

时间:2012-01-16 03:48:41

标签: c# generics

如果我有以下方法;

private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact)

因此,我可以使用FileClientFileContact模型传入此方法。

两者都有一个名为Contact的属性,它也是一个模型以及两者之间不常见的其他属性。

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

Contact sourceContact = fileClientOrContact.Contact;

但是,鉴于这是通用的,它不知道Contact中有TSource个对象。

我的限制是我无法针对FileClientFileContact设置界面。我基本上无法触及这些模型。

如何从TSource获取联系人对象?我可以用某种方式使用反射吗?

6 个答案:

答案 0 :(得分:2)

您可以使用Visitor pattern来包装这两个类,并让两个访问者类继承自公共接口。

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

答案 1 :(得分:2)

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

private TSource CopyFileClientModel<TSource>(TSource fileClientOrContact)
(
    dynamic d = fileClientOrContact;

    // Now you reach the Contact property
    var x = d.Contact;
)

明智的做法是验证typeof(TSoruce)FileClient还是FileContact

你可以做的另一件事是包装这两个类。请参阅维基百科中的adapter design pattern


但也许Generics不是你的解决方案。为什么不在FileClientFileContact使用Method重载。你的方法签名接受任何TSource,但是当方法得到int,long,Person它无效时,如果你可以将Generics限制为你期望的类型,那么TSource不是正确的解决方案

请改用Method overload。并保存那些“创意解决方案”

答案 2 :(得分:2)

您可以传递函数以返回联系人。

例如:

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...
}

答案 3 :(得分:1)

喜欢什么?

if (fileClientorContact is FileContact)
    return fileClientorContact as Contact;
else
    return ((Client)fileClientorContact).Contact;

当然,这假设fileClientorContact中的“联系人”与您要返回的类型相同。或者,如果两种类型都按照您在问题中的建议定义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;

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

答案 4 :(得分:1)

如果您使用的是C#4.0,则可以使用动态

 dyanmic obj = fileClientOrContact;
 Contact sourceContact = obj.Contact;

但这并不理想! (它可能导致运行时异常)


修改

或者,我可能会为每种类型使用两个重载函数,每个函数调用共享功能的公共函数。

答案 5 :(得分:0)

如果FileContactFileClient没有共享.Contact的祖先,并且您无法为其实现公共接口,并且您真的想要使用反射,那么您可以做像这样的东西:

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