簡體   English   中英

C#中的變量泛型返回類型

[英]Variable generic return type in C#

有沒有辦法讓方法從方法中返回許多泛型類型中的任何一個? 例如,我有以下內容:

public static T ParseAttributeValue<T>(this XElement element, string attribute)
    {
        if(typeof(T) == typeof(Int32))
        {
            return Int32.Parse(element.Attribute(attribute).Value);
        }

        if(typeof(T) == typeof(Double))
        {
            return Double.Parse(element.Attribute(attribute).Value);
        }

        if(typeof(T) == typeof(String))
        {
            return element.Attribute(attribute).Value;
        }

        if(typeof(T) == typeof(ItemLookupType))
        {
            return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
        }
    }

(這只是一個非常快速的模型,我知道任何生產代碼都需要在空檢查等方面更加徹底......)

但編譯器不喜歡它,抱怨Int32不能隱式轉換為T (它也不能用於強制轉換)。 我能理解。 在編譯時,它無法知道T是什么,但我事先檢查它。 無論如何我能做到這一點嗎?

我以前做過這些類型的泛型方法。 獲得類型推斷的最簡單方法是提供通用轉換器函數。

public static T ParseAttributeValue<T>
          (this XElement element, string attribute, Func<string, T> converter)
{
  string value = element.Attribute(attribute).Value;
  if (String.IsNullOrWhiteSpace(value)) {
    return default(T);
  }

  return converter(value);
}

您可以像下面這樣使用它:

int index = element.ParseAttributeValue("index", Convert.ToInt32);
double price = element.ParseAttributeValue("price", Convert.ToDouble);

您甚至可以提供自己的功能並享受世界上所有的樂趣(甚至返回匿名類型):

ItemLookupType lookupType = element.ParseAttributeValue("lookupType",
  value => Enum.Parse(typeof(ItemLookupType), value));

var item = element.ParseAttributeValue("items",
  value => {
    List<string> items = new List<string>();
    items.AddRange(value.Split(new [] { ',' }));
    return items;
  });

.Net已經有一堆很棒的字符串轉換例程你可以使用! TypeConverter可以為您完成大部分繁重的工作。 然后,您不必擔心為內置類型提供自己的解析實現。

請注意,如果您需要處理在不同文化中表達的解析值,可以使用TypeConverter上的API的語言環境感知版本。

以下代碼將使用默認區域性解析值:

using System.ComponentModel;

public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
    var converter = TypeDescriptor.GetConverter(typeof(T));
    if (converter.CanConvertFrom(typeof(string)))
    {
        string value = element.Attribute(attribute).Value;
        return (T)converter.ConvertFromString(value);
    }

    return default(T);
}

這適用於許多內置類型,您可以使用TypeConverterAttribute修飾自定義類型,以允許它們也參與類型轉換游戲。 這意味着將來您將能夠解析新類型,而無需更改ParseAttributeValue的實現。

請參閱: http//msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx

為什么要使用type參數作為返回類型? 這可以工作,只需要在調用后進行強制轉換:

public static Object ParseAttributeValue<T>(this XElement element, string attribute)
{
    if(typeof(T) == typeof(Int32))
    {
        return Int32.Parse(element.Attribute(attribute).Value);
    }

    if(typeof(T) == typeof(Double))
    {
        return Double.Parse(element.Attribute(attribute).Value);
    }

    if(typeof(T) == typeof(String))
    {
        return element.Attribute(attribute).Value;
    }

    if(typeof(T) == typeof(ItemLookupType))
    {
        return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
    }
}

或者更好的是:

public static Int32 ParseAsInt32(this XElement element, string attribute)
{
    return Int32.Parse(element.Attribute(attribute).Value);
}

// etc, repeat for each type

第二種方法的另一個好處是具有更高的內聯可能性,而且(對於像Int32這樣的值類型)會阻止對值進行打包/取消裝箱的需要。 這兩種方法都會使該方法的執行速度更快一些。

不確定這是否正是您想要的,但如果您先將objectT則可以使返回有效

    public static T ParseAttributeValue<T>(this XElement element, string attribute)
    {
        if (typeof(T) == typeof(Int32))
        {
            return (T)(object)Int32.Parse(element.Attribute(attribute).Value);
        }

        if (typeof(T) == typeof(Double))
        {
            return (T)(object)Double.Parse(element.Attribute(attribute).Value);
        }

        if (typeof(T) == typeof(String))
        {
            return (T)(object)element.Attribute(attribute).Value;
        }

        return default(T);
    }

但是你仍然需要在編譯時提供T ,調用方法如下:

int value = element.ParseAttributeValue<int>("attribute");

這有兩種方式......

    static T ReadSetting<T>(string value)
    {
        object valueObj = null;
        if (typeof(T) == typeof(Int32))
            valueObj = Int32.Parse(value);
        return (T)valueObj;
    }
    static dynamic ReadSetting2<T>(string value)
    {
        if (typeof(T) == typeof(Int32))
            return Int32.Parse(value);
        throw new UnsupportedException("Type is unsupported");
    }
    static void Main(string[] args)
    {
        int val1 = ReadSetting<Int32>("2");
        int val2 = ReadSetting2<Int32>("3");
    }

使用C ++模板,這種方法可行,但前提是每條代碼都在不同的單獨特化中。 使這項工作的事情是未編譯未使用的函數模板(或更准確:未完全實例化),因此如果模板的副本使用不同類型實例化,則一段代碼無效的事實不會上來。

C#是不同的,AFAIK沒有針對泛型的專業化。 在C#的限制下工作的一種方法是完成你想要做的事情,就是創建一個具有更抽象的返回類型的函數,並使用ParseAttributeValue只將它強制轉換為T.

所以你會:

private static Object AbstractParseValue(System.Type t, XElement element, string attribute)

public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
     return (T)AbstractParseValue(typeof(T), element, attribute);
}

我建議不要每次執行例程時測試類型參數,你應該創建一個類似這樣的通用靜態類:

internal static class ElementParser<T>
{
  public static Func<XElement, string, T> Convert = InitConvert;

  T DefaultConvert(XElement element, string attribute)
  {
    return Default(T); // Or maybe throw exception, or whatever
  }

  T InitConvert(XElement element, string attribute)
  {
    if (ElementParser<int>.Convert == ElementParser<int>.InitConvert)
    {  // First time here for any type at all
      Convert = DefaultConvert; // May overwrite this assignment below
      ElementParser<int>.Convert =
        (XElement element, string attribute) =>
          Int32.Parse(element.Attribute(attribute).Value);
      ElementParser<double>.Convert =
        (XElement element, string attribute) =>
          Int32.Parse(element.Attribute(attribute).Value);
      // etc. for other types
    }
    else // We've done other types, but not this type, and we don't do anything nice for it
    {
      Convert = DefaultConvert;
    }
    return Convert(element, attribute);      
  }
}
public static T ParseAttributeValue(this XElement element, string attribute)
{
  ElementParser<T>.Convert(element, attribute);
}

使用這種方法,只需在第一次使用特定類型時進行特殊處理。 之后,可以僅使用單個通用委托調用來執行轉換。 一旦可以輕松添加任意數量的類型,甚至允許轉換器在運行時注冊任何所需類型。

暫無
暫無

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

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