【问题标题】:C# convert System.Func<Tderived, bool> to System/Func<Tbase, bool>C# 将 System.Func<Tderived, bool> 转换为 System/Func<Tbase, bool>
【发布时间】:2017-02-15 15:13:33
【问题描述】:

我用谷歌搜索,但找不到满意的答案。我基本上是想让这段代码工作:

public List<WordEntry> WordDataBase = new List<WordEntry>();
public List<CharacterEntry> CharacterDataBase = new List<CharacterEntry>();

public List<Entry> SelectWhere<T>(System.Func<T, bool> predicate) where T : Entry
{
    if (typeof(T) == typeof(WordEntry))
        return WordDataBase.Where(predicate);
    else if (typeof(T) == typeof(CharacterEntry))
        return CharacterDataBase.Where(predicate);
    else
        return null;
} 

在此示例中,WordEntry 和 CharacterEntry 均派生自 Entry。我得到编译器错误:

Error   CS1503  Argument 2: cannot convert from 'System.Func<T, bool>' to 'System.Func<WordEntry, int, bool>'   

Error   CS1503  Argument 2: cannot convert from 'System.Func<T, bool>' to 'System.Func<CharacterEntry, int, bool>'

希望你能帮我解决这个问题。提前致谢

【问题讨论】:

  • 我认为这作为一种方法有点毫无意义。如果您有 2 种类型,则有两种方法。
  • 如果您对泛型类型进行类型检查,那么您几乎总是做出了糟糕的设计选择。
  • 我会说它与类型变化有关——编译器不允许隐式转换为父类型。
  • 好的,谢谢大家的回答。但是我看到很多人回复我写的具体功能。但是,此功能只是我要实现的基本版本。在最终版本中,我想根据 func 的转换设置一个更加复杂和动态的系统。所以每个人都可以忽略 if/else 语句的函数,只使用两种类型。谢谢

标签: c# linq func derived


【解决方案1】:

基本上,您只需要转换 - 语言规则不允许编译器在考虑所涉及的类型时考虑 if 语句。请注意,您需要调用ToList&lt;Entry&gt;(),指定类型参数以避免获得List&lt;WordEntry&gt;List&lt;CharacterEntry&gt;

public List<Entry> SelectWhere<T>(Func<T, bool> predicate) where T : Entry
{
    if (typeof(T) == typeof(WordEntry))
        return WordDataBase
            .Where((Func<WordEntry, bool>) predicate)
            .ToList<Entry>();
    else if (typeof(T) == typeof(CharacterEntry))
        return CharacterDataBase
            .Where((Func<CharacterEntry, bool>) predicate)
            .ToList<Entry>();
    else
        return null;
}

我建议您不要将其设为通用,而是只使用两种不同的方法。感觉它真的不是一个通用方法,因为它只适用于两种非常特定的类型。

【讨论】:

  • 感谢您的回答。但是我之前尝试过强制转换函数。但部分: (Func)predicate 给出错误:错误 CS0030 无法将类型 'System.Func' 转换为 'System.Func'
  • @user1370286:啊,你可能需要先转换到object。将添加。
  • @user1370286:实际上,不,我的代码编译得很好。它真的应该没问题 - 将创建一个要点来展示......
  • @user1370286: gist.github.com/jskeet/1c63090d847a97cc757352807cfc0a50 编译没有错误。
【解决方案2】:

您的方法 SelectWhere 根据参数的类型执行不同的操作 - 那么为什么不直接使用重载方法

public List<WordEntry> SelectWhere(Func<WordEntry, bool> predicate)
{
    return WordDataBase.Where(predicate);
} 

public List<CharacterEntry> SelectWhere(Func<CharacterEntry, bool> predicate)
{
    return CharacterDataBase.Where(predicate);
}

然后你可以使用这些方法而无需强制转换和“可怕的”if...else 语句

Func<WordEntry, bool> isValid = word => word.SomeProperty > 0;
var filteredWords = SelectWhere(isValid); // WordDataBase will be used

Func<CharacterEntry, bool> IsValid = character => character.SomeProperty != null;
var filteredCharacters = SelectWhere(IsValid); //CharacterDataBase will be used

【讨论】:

    【解决方案3】:

    根据您显示的错误,我认为您的谓词声明错误。

    您的两个 Database 对象上的 where 子句都需要 Func&lt;T, int, bool&gt;,请注意第二个参数是 int,因此像这样更改您的扩展方法应该是进步的正确的方向

    public List<Entry> SelectWhere<T>(Func<T, int, bool> predicate) where T : Entry
    

    注意:您已经声明了泛型方法,其中您的代码依赖于泛型类型,这使得代码不那么通用,请查看@Fabio 的答案,我认为他有必要创建单独的扩展方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多