“ T”不包含“ Foo”的定义,最佳扩展方法重载需要类型为“ IType”的接收器

时间:2019-11-04 13:40:05

标签: c# .net .net-core

我有这样的代码:

using System;
using System.Collections.Generic;
using System.Linq;

public interface IMyString
{
    string Id {get;set;}
};

public class MyString : IMyString
{
    public string Id {get;set;}
}

public static class Extensions
{
    public static IEnumerable<IMyString> WithId(this IEnumerable<IMyString> source, string id)
    {
        return source.Where(x => x.Id == id);
    }
}

public class Program
{
    private static List<T> GetMyStrings<T>(string key, List<T> input)
        where T: IMyString
    {
        return input.WithId(key).ToList();
    }

    public static void Main()
    {
        var foo = new List<MyString>{ new MyString { Id = "yes"}, new MyString { Id = "no" } };
        var result = GetMyStrings("yes", foo);
        var result2 = foo.WithId("no");
        Console.WriteLine(result2);
    }
}

为什么input.WithId(key).ToList()可以,但foo.WithId("no")会导致语法错误?有没有办法使方法GetMyStrings起作用?

2 个答案:

答案 0 :(得分:5)

在没有代码上下文的情况下,很难提供太多帮助,但是这两种方法的类型约束是不同的。您有两种选择:

选项1:

cdk-visually-hidden

选项2:

public static class Extensions
{
    public static IEnumerable<T> WithId<T>(this IEnumerable<T> source, string id) where T: IMyString
    {
        return source.Where(x => x.Id == id);
    }
}

这是dotnetfiddle,其中第二个选项是有效的代码段:

答案 1 :(得分:2)

这里的问题是,只要WithId()是非泛型的,那么它可以返回的全部是IEnumerable<IMyString>。但是,GetMyStrings()需要返回IEnumerable来实现IMyString或从 IMyString派生的任何接口。

考虑:

public interface IMyOtherString : IMyString
{
    int LOL { get; set; }
}

public class AnotherString : MyString, IMyOtherString
{
    public int LOL { get; set; }
}

AnotherString实现了IMyString,因此就GetMyStrings()而言,此“应该”工作:将采用该参数类型并返回该返回类型。

var foo = new List<AnotherString> { 
    new AnotherString { Id = "yes" }, new AnotherString { Id = "no" } };
List<IMyOtherString> result = GetMyStrings("yes", foo);

问题在于,GetMyStrings()现在必须要求WithId()返回IEnumerable<IMyOtherString>,但是该返回类型不会重载WithId()。您定义的WithId()不是一个选项:它可以使用IEnumerable<IMyOtherString>作为参数,但随后会将枚举中的所有内容强制转换回IMyString

peinearydevelopment的答案(选项1是您应该使用的答案;选项2在上述情况下无效)通过将WithId()GetMyStrings()放在同一类型参数页面上来解决此问题。

这是它的外观。无需返回List<T>。如果需要,调用者可以在其上调用ToList()。

public static IEnumerable<T> WithId<T>(this IEnumerable<T> source, string id) 
    where T : IMyString
{
    return source.Where(x => x.Id == id);
}