【问题标题】:How to dynamically cast a list of based type to derived type如何将基于类型的列表动态转换为派生类型
【发布时间】:2016-11-06 23:55:54
【问题描述】:

我有一个具有以下层次结构的 dll:

Interface ISchema {}

class Schema:ISchema{}

class TableSchema:Schema{}

class ViewSchema:Schema{}

我有另一个具有以下层次结构的 dll:

Interface ISearch {}

class Table:ISearch{}

class View:ISearch{}

以下代码是根据用户选择触发对Table或View的搜索操作:

private void FindNowButton_Click(object sender, EventArgs e)
{
    // return Table or View according to user selection. (Property is an internal class helping to retrieve the selected type)
    var type = (ObjectsTypeComboBox.SelectedItem as Property).Type;

    // Create an instance of table or View as ISearch
    var instance = (ISearch)Activator.CreateInstance(type);

    // Call to relevant Search (table.Search or View.Search)
    // _dataManager help to get the records from Schema hierarchy
    // text is the text to search
    var result = instance.Search(_dataManager, FindWhatTextBox.Text);

    // Show in DataGridView the result
    FindResultsDGV.DataSource = result;
}

每个搜索方法都返回一个列表。我需要在网格上显示不同的列。 TableSchema 和 ViewSchema 有不同的属性,下面的转换就可以了。

FindResultsDGV.DataSource = result.Cast<TableSchema> ; // or result.Cast<ViewSchema>

在这个阶段如何动态获取正确的类型?

欢迎任何其他解决方案

更新:

根据@GiladGreen

public interface ISearchSchemaFactory
{
    ISearch<ISchema> GetSearch(Type schemaType);
}

public class Factory : ISearchSchemaFactory
{
    public ISearch<ISchema> GetSearch(Type schemaType)
    {
        if (schemaType.Equals(typeof(Table)))
        {
            return new BL.AdvancedSearch.Table(); // Getting an error here
           // Cannot implicitly convert type 'Table' to 'ISearch<ISchema>'. An explicit conversion exists (are you missing a cast?) 
        }
        else if (schemaType.Equals(typeof(View)))
        {
            // TODO
        }

        return null; // TODO
    }
}

【问题讨论】:

  • 你考虑过使用泛型吗?

标签: c# .net oop interface polymorphism


【解决方案1】:

我建议您将 ISearch 更改如下:

Interface ISearch<out TSchema> where TSchema: ISchema
{
    TSchema Search(....);   
}

class Table : ISearch<TableSchema>
{
    public TableSchema Search(....)
    {
        //Some searching code
    }
}

class View:ISearch<ViewSchema>
{
    public ViewSchema Search(....)
    {
        //Some searching code
    }
}

那么你还可以做的是有一个ISearchSchemaFactory,它会根据你给它的TSchema给你一个正确的ISearch的实例:

public interface ISearchSchemaFactory
{
    ISearch<ISchema> GetSearch(Type schemaType);
}

以及用法:var search = factory.GetSearch(type);


工厂实现示例

public class MappingSearchSchemaFactory : ISearchSchemaFactory
{
    public MappingSearchSchemaFactory(Dictionary<Type, ISearch<ISchema>> mapping)
    {
        Mapping = mapping;
    }

    ISearch<ISchema> GetSearch(Type schemaType)
    {
        ISearch<ISchema> result;
        if(!Mapping.TryGetValue(schemaType, out result)
        {
            //Some logging or throwing exception behavior - depends what you want
        }
        return result;
    }
    public Dictionary<Type, ISearch<ISchema>> Mapping { get; set; }
}

此特定实现为“某人”获取映射。一个可能的初始化代码可以是:

ISearchSchemaFactory factory = new MappingSearchSchemaFactory(
    new Dictionary<Type,ISearch<ISchema>>
    { new TableSchema(), new Table() },
    { new ViewSchema(), new view() }
);

但我不太推荐这个。我会去看看Dependency InjectionIoC Containers 来管理我的对象的初始化。我个人使用Castle Windsor

【讨论】:

  • 您将不得不像这样调用GetSearch 方法GetSearch&lt;ViewSchema&gt;()GetSearch&lt;TableSchema&gt;() 所以问题仍然存在。
  • 是的。编辑了工厂的方法。
  • 现在你的方法不是通用的,所以ISearch&lt;ISchema&gt; GetSearch(Type schemaType); 不会编译。
  • @ehh - 已修复。看看我定义ISearch 接口的那一行——我忘了​​添加“out”。见Covariance and Contravariance (C#)
  • @GiladGreen,您的解决方案效果很好!你是对的,我错过了接口 ISearch。非常感谢您的耐心与合作。和你聊天很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 2016-02-26
  • 1970-01-01
  • 1970-01-01
  • 2012-12-06
  • 2010-09-12
相关资源
最近更新 更多