4

I have the below code example where I want to prepend some text on to the front of the source param which could be of type ISite or IFactory used in a MVC drop down list via a MoreLinq extension. This function is used in a controller action that returns the list serialised as JSON so that it can be loaded dynamically using some dropdown cascading, otherwise I would have done this separately in a view model.

I was wondering if there is a way to be able to do something similar to the below without having to create a concrete ListItem class, my example shows how I am using as IListItem but I am aware this won't compile.

At the moment my controller has no concept of any of my model's concrete classes and I kind of wanted to keep it that way and I'm not sure if I definately need to make an instance of a ListItem to make this work or if anyone has another suggestion?

My knowledge of Covariance and Contravariance in Generics is limited, in case that is of importance here? Thanks

    public interface IListItem
    {
        int Id { get; set; }
        string Name { get; set; }
    }

    public interface ISite : IListItem
    {
        int CountryId { get; set; }
    }

    public interface IFactory : IListItem
    {
        int SiteId { get; set; }
    }

    public interface IResource
    {
        int Id { get; set; }
        string Name { get; set; }
        int ContentID { get; set; }
        string Text { get; set; }
        int LanguageID { get; set; }
        string LanguageCode { get; set; }
        int Priority { get; set; }
    }

private IEnumerable<IListItem> PrependSelectionResource(IEnumerable<IListItem> source, string languageCode)
{
    if(source == null || source.Count() == 1)
        return source; // don't bother prepending the relevant resource in these cases

    try
    {
        // will throw an exception if languageCode is null or blank
        var resource = _resourceRepository.GetByNameAndLanguageCode(
            "Prompt_PleaseSelect",
            languageCode);

        if(resource == null)
            return source;

        // prepend the "Please Select" resource to the beginning of the source
        // using MoreLinq extension
        return source.Prepend(new {
            Id = 0,
            Name = resource.Text ?? ""
        } as IListItem);
    }
    catch {
        return source;
    }
}
4

2 回答 2

3

不幸的是,您无能为力。您必须将实现IListItem接口的类的具体实例传递给Prepend方法。

如果您担心在应用程序的其他地方公开实现,您可以为您的文件创建一个本地实现PlaceholderListItem并使用它。

于 2013-01-05T17:06:48.947 回答
2

匿名类型(如new { Id = 0, Name = resource.Text ?? "" })是不实现任何接口的类(除了 之外没有其他基类object)。所以它不会工作。

如果您使用模拟框架,您可以创建一个模拟,它是一些神奇生成的实现接口的类。有时也称为存根

但是在这种情况下,编写自己的 mock 真的很容易,当然:

class ListItemMock : IListItem
{
  public int Id { get; set; }
  public string Name { get; set; }
}

然后你可以用一个对象初始化器来实例化它:new ListItemMock { Id = 0, Name = resource.Text ?? "", }

于 2013-01-05T17:27:56.540 回答