簡體   English   中英

將無約束傳遞的泛型類型與受約束的泛型類型一起使用

[英]Using a generic type passed without constraint with a constrained generic type

假設我們有以下類:

public interface IFrobnicator<T> { }

class ComparableFrobnicator<T> : IFrobnicator<T> where T : IComparable<T>
{
    public ComparableFrobnicator(T value) { }
}

class EquatableFrobnicator<T> : IFrobnicator<T> where T : IEquatable<T>
{
    public EquatableFrobnicator(T value) { }
}

你可以寫方法

public IFrobnicator<T> MakeFrobnicatorFromComparable<T>(T value) where T : IComparable<T>
{
    return new ComparableFrobnicator<T>(value);
}

public IFrobnicator<T> MakeFrobnicatorFromEquatable<T>(T value) where T : IEquatable<T>
{
    return new EquatableFrobnicator<T>(value);
}

如果我想將其統一為一個方法,最明顯的方法將無法編譯:

public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
    if (value is IComparable<T>)
    {
        return new ComparableFrobnicator<T>(value);
    }
    else if (value is IEquatable<T>)
    {
        return new EquatableFrobnicator<T>(value);
    }
    else throw new ArgumentException();
}

編譯時會引發以下錯誤:

CS0314 類型“T”不能用作泛型類型或方法“UserQuery.ComparableFrobnicator”中的類型參數“T”。 沒有從“T”到“System.IComparable”的裝箱轉換或類型參數轉換。

我不能用new ComparableFrobnicator<IComparable<T>>替換new ComparableFrobnicator <T> ,因為這會導致取回value問題 - 您不能從接口類型轉換為具體類型。

所以相反,我走的是反思路線:

public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
    if (value is IComparable<T>)
    {
        var constructor = typeof(ComparableFrobnicator<>).MakeGenericType(typeof(T)).GetConstructor(new[] { typeof(T) });
        return (IFrobnicator<T>)constructor.Invoke(new object[] { value});
    }
    else if (value is IEquatable<T>)
    {
        var constructor = typeof(EquatableFrobnicator<>).MakeGenericType(typeof(T)).GetConstructor(new[] { typeof(T) });
        return (IFrobnicator<T>)constructor.Invoke(new object[] { value });
    }
    else throw new ArgumentException();
}

這似乎工作得很好,但在我習慣的具有如此強大類型推斷的語言中,這看起來像是倒退了一步。 是否有我遺漏的東西,或者我遺漏了更好的技術?

嘗試擴展方法方法,實現value.MakeFrobnicator()的方式有助於解決泛型類型參數問題

public interface IFrobnicator<T> { }

public class ComparableFrobnicator<T> :IFrobnicator<T> 
                              where T  :IComparable<T> 
 {
    public ComparableFrobnicator(T param) { }
 }

public class EquatableFrobnicator<T> :IFrobnicator<T>
                              where T : IEquatable<T> 
{
   public EquatableFrobnicator(T value) { }
}

 public static class FrobnicatorExtentions
 {
    public static IFrobnicator<T> 
          MakeFrobnicatorFromComparable<T>(this T value)
    where T: IComparable<T>
    {                                                            
      //return new ComparableFrobnicator<T>(value);      
     return value.MakeFrobnicator();
    }

    public static IFrobnicator<T> 
           MakeFrobnicatorFromEquatable<T>(this T value)
    where T : IEquatable<T>
    {
      // return new EquatableFrobnicator<T>(value);
     return value.MakeFrobnicator();
    }  

    public static IFrobnicator<T> 
                  MakeFrobnicator<T>(this IEquatable<T> value) 
    where T: IEquatable<T>
    {
      if (value is T)
      {
        if (value is IEquatable<T>)
        {
          return new EquatableFrobnicator<T>((T)value);
        } 
      }

     throw new InvalidCastException();
    }

   public static IFrobnicator<T> 
                 MakeFrobnicator<T>(this IComparable<T> value) 
   where T : IComparable<T>
  {
     if (value is T)
     {
       if (value is IComparable<T>)
       {
         return new ComparableFrobnicator<T>((T)value);
      }
     }

    throw new InvalidCastException();
  }

}

你試過做演員嗎?

public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
    if (value is IComparable<T>)
    {
        return new ComparableFrobnicator<T>((IComparable<T>)value);
    }
    else if (value is IEquatable<T>)
    {
        return new EquatableFrobnicator<T>((IEquatable<T>)value);
    }
    else throw new ArgumentException();
}

如果這完全有效,我不記得我的頭頂。 無論哪種方式,它都不是很開放/封閉。 您可以編寫一個轉換器列表,每個轉換器決定它們是否適合進行轉換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM