我可以将未知对象转换为接口,以便可以在C#中访问其属性吗?

时间:2012-03-22 14:01:46

标签: c# asp.net-mvc generics interface

我正在尝试不重复代码,所以我有一个方法可以快速转换接口的属性。

我有3个使用此接口的具体类,我希望它们都可以使用此方法。

当我从Session中获取其中一个对象时出现问题。我认为没有办法正确地施放它。

public ActionResult GetItems()
{
     details = (IHeader<IDetail>)Session["SelectedHeader"].Details // Throws invalid cast
     return Json(details);
}

// My interface and class examples:
interface IHeader<T> where T: IDetail
{
     IList<T> Details { get; set; }
}

class ConcreteHeader : IHeader<ConcreteDetail>
{
     public IList<ConcreteDetail> Items { get; set; }
}

class ConcreteDetail : IDetail
{
    ...
}

我不能使用泛型,因为这是ASP.NET MVC 3中的一个动作方法(除非有一个技巧)。这是可能的,还是我必须为每个类编写一个方法?

编辑:不确定原始问题是否清楚:

进入会话的是任何一个具体对象:

Session["SelectedHeader"] = new ConcreteHeader() { Details = new List<ConcreteDetail>() };

3 个答案:

答案 0 :(得分:5)

你需要用括号括起你的演员:

details = ((IHeader<IDetail>)Session["SelectedHeader"]).Details;

答案 1 :(得分:2)

如果您使用的是.NET 4.0,只需使用dynamic关键字进行投射,以确保正确的自动类型解析:

// note intellisense won't work when you use dynamic keyword...
var details = ((dynamic)Session["SelectedHeader"]).Details;

答案 2 :(得分:2)

好像你刚刚遇到了共同和逆变的奇妙世界。我写了a blog post about it,试图尽可能简单地解释它。

结论:在.NET 4.0之前,您无法将IHeader<ConcreteDetail>强制转换为IHeader<IDetail>

从.NET 4.0开始,您可以使用inout关键字来实现此目的。您可以将界面定义为interface IHeader<out T>

如果您还没有使用.NET 4.0,可以通过创建一个新的lambda来解决这个问题:

details = () => Session["SelectedHeader"].Details;