【问题标题】:Delegate Method parameter from IEnumerable<T> to specific type将方法参数从 IEnumerable<T> 委托给特定类型
【发布时间】:2017-08-04 13:11:21
【问题描述】:

我发现了这个问题: Is it possible to specify a generic constraint for a type parameter to be convertible FROM another type? 我正在寻找更聪明的方法。

Class A {
     public A(string){}
}

Class foo
{
    private List<A> content = new List<A>();

    public void Add(A a){
        content.Add(a);
    }
    public void Add(string str){
        content.Add(new A(str));
    }
    public void AddRange<T>(IEnumerable<T> iterable) // where T : ???
    {
        foreach(T t in iterable)
            content.Add((A)t); //Error
    }
}

错误是:

无法将类型“T”转换为“A”

问题:是否存在像“convertable”这样的where T : ? 表达式?

更新: 我有两个方法重载: Add(A)Add(string) 目前我尝试将 T 转换为 A。但我的主要问题是,我想使用与 T 相关的不同 Addmethods。 我需要的是这样的:

public void AddRange<T>(IEnumerable<T> iterable) where T : Add(T) 
{
    foreach (T t in iterable)
        this.Add(t);
}

【问题讨论】:

  • 不清楚您要达到的目标。你不想要where T : A吗?
  • “可转换”是什么意思?
  • 我想用两种不同的可枚举类型调用 Add:List 和 List
  • @Rahul,我做到了,但错误仍然存​​在。但T 可能就是一切。例如整数是不可转换的。所以错误是可以的。我需要限制T 来解决它。我不知道该怎么说:T 是所有可以转换(impl/expl)为A 的类型。

标签: c# generics ienumerable


【解决方案1】:

我认为您正在寻找的约束类型必须具有显式运算符T,但由于规范说:

转换操作符声明符:
    隐式运算符 type ( type identifier )
    显式运算符 type (type identifier)

这通常意味着你不能有通用的显式和隐式运算符,我认为这是不可能的。

如果你有一些具体的类型,你可以让你的案例成为可能:

public class A
{
    public static explicit operator B(A a)
    {
        return new B();
    }
}

public class B { }

public class Convert
{
    public static T To<T>(dynamic obj)
    {
        return (T) obj;
    }
}

class Foo
{
    private List<A> content = new List<A>();
    public void AddRange<T>(IEnumerable<T> iterable) where T : B
    {
        foreach (T t in iterable)
            content.Add(Convert.To<A>(t)); // This will invoke the implicit operator defined in A
    }
}

也许您可以将泛型 T 类型抽象为 B 类型并像那样对其进行约束,或者您可以定义所有类型的隐式运算符,希望您在类型 T 中转换为 A。

【讨论】:

    【解决方案2】:

    如果您希望 T 成为 A 类型或任何派生类型,请使用 where T : A

    编辑(在您发表评论后):

    如果你想让T 成为AString,你不能这样做:where T : A, String。只能约束类、接口、类型,不能做OR操作。

    因此,如果您只需要StringA,那么您应该使用不同的实现。如果你想要任何课程 - where T : class

    【讨论】:

    • 我收到此错误:“字符串”不是有效的约束。用作约束的类型必须是接口、非密封类或类型参数。
    • @Syrlia,你什么时候收到这个错误?如果您尝试约束只接受String,您将失败,因为Stringsealed,并且不允许对sealed 类进行约束(没有理由)。说不同的实现,我的意思是两个重载 - 如果你只想要两种类型,你应该有两个重载 - 在这种情况下不需要泛型。
    • 另外两个实现没问题,但我想为更大的情况学习它。这只是一个例子。 ;-) 将其更改为:AddRange&lt;T&gt;(IEnumerable&lt;T&gt; iterable) where T : A, string 时出现错误
    • @Syrlia,但您不能指定两个类约束(参见答案)。如果你真的需要泛型,那么你应该在你提供的链接中使用答案。
    【解决方案3】:

    你可以用 A 代替 T:

    public void Add(IEnumerable<A> iterable)
    {
       foreach(A t in iterable)
          content.Add(t);
    }
    

    和:

    public void Add(IEnumerable<string> iterable)
    {
       foreach(string t in iterable)
          content.Add(t);
    }
    

    【讨论】:

    • 如果我这样做并尝试调用 AddRange(new List&lt;string&gt;():“参数 1:无法从 'System.Collections.Generic.List' 转换为 System.Collections.Generic.IEnumerable' "
    • 你必须添加两个方法,因为'string'不是一个有效的约束(对于where子句),因为它是一个密封的类。
    猜你喜欢
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多