タイプ「Int」を「T」に暗黙的に変換することはできません


92

電話Get<int>(Stat);またはGet<string>(Name);

しかし、コンパイルすると、次のようになります。

タイプ「int」を「T」に暗黙的に変換することはできません

と同じことstring

public T Get<T>(Stats type) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        int t = Convert.ToInt16(PlayerStats[type]);
        return t;
    }
    if (typeof(T) == typeof(string))
    {
        string t = PlayerStats[type].ToString();
        return t;
    }
}

6
ifブロックがTがintであることを確認したので、ブロック内でTがintであり、暗黙的にintをTに変換できるはずだと考えているかもしれません。しかし、コンパイラはその理由に従うようには設計されていません。通常、Tはintから派生しないため、暗黙的な変換は許可されません。(コンパイラがサポートしている場合、ベリファイアはサポートしないため、コンパイルされたアセンブリは検証できません。)
JGWeissman 2011年

回答:


132

ジェネリックのタイプをオンに切り替えていることに気付いたときはいつでも、ほぼ間違いなく何か間違ったことをしています。ジェネリック医薬品は、する必要があり、一般的なタイプに関係なく、まったく同じように動作する必要があります。

Tがintまたはstringのみである場合は、そもそもこのようにコードを記述しないでください。2つのメソッドを記述します。1つはintを返し、もう1つは文字列を返します。


1
車がIConvertibleを実装しているGet <Car>は、破損の原因になります。誰かがあなたがジェネリックメソッドを持っているのを見ると、彼らはIConvertibleを実装するものなら何でも渡すことができると思います。
tjaart 2012

11
@Ericさん、部分的にしか同意できません。XMLタグに格納されている配列を解析する必要がある状況があります。問題は、XMLドキュメントが従う仕様(私の場合はCOLLADA)で、そのような配列はfloat、int、boolだけでなく、いくつかのカスタムタイプもあります。ただし、float [](array-tagsには名前に格納されているデータのタイプが含まれています:float_arrayはfloatを格納します)を取得した場合は、文字列をの配列として解析する必要があります。 floats。IFormatProviderを使用する必要があります。明らかに「T.Parse(...)」は使用できません。そのため、一部のケースでは、このような切り替えを使用する必要があります。
rbaleksandar 2013

1
この答えはあなたをうさぎの穴から遠ざけるでしょう。の汎用関数を作りたかったのですが、int, int?, bool, bool?, string無理そうです。
ジェス

これにより、ジェネリック列挙型の切り替えが実用的になります。
デビッドA.グレイ

1
私はこれを答えとして使いたくありませんでした。しかし、彼は正しい。タイプを確認し、特定のタイプの場合はプロパティを設定したかったのです。解決策は、強く型付けされたパラメーターをとるメソッドを作成することでした。
MattDawdy19年

143

Convert.ChangeType()カスタムコードの代わりに使用できるはずです。

public T Get<T>(Stats type) where T : IConvertible
{
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}

22
どうですかreturn (T)(object)PlayerStats[type];
maxp 2015年

10
public T Get<T>(Stats type ) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        int t = Convert.ToInt16(PlayerStats[type]);
        return (T)t;
    }
    if (typeof(T) == typeof(string))
    {
        string t = PlayerStats[type].ToString();
        return (T)t;
    }
}

2
return (T) t;nullチェックは必要ないからです。
BoltClock

上記は私のためにコンパイルされません。Tは、「as」をコンパイルするための参照型である必要があります。
ロバートシュミット

9

ChangeTypeおそらくあなたの最良の選択肢です。私のソリューションは、BrokenGlassが提供するソリューションと似ていますが、トライキャッチロジックが少しあります。

static void Main(string[] args)
{
    object number = "1";
    bool hasConverted;
    var convertedValue = DoConvert<int>(number, out hasConverted);

    Console.WriteLine(hasConverted);
    Console.WriteLine(convertedValue);
}

public static TConvertType DoConvert<TConvertType>(object convertValue, out bool hasConverted)
{
    hasConverted = false;
    var converted = default(TConvertType);
    try
    {
        converted = (TConvertType) 
            Convert.ChangeType(convertValue, typeof(TConvertType));
        hasConverted = true;
    }
    catch (InvalidCastException)
    {
    }
    catch (ArgumentNullException)
    {
    }
    catch (FormatException)
    {
    }
    catch (OverflowException)
    {
    }

    return converted;
}

私のユースケースは、ジェネリック抽象クラスから派生した具象クラスです。このクラスは、基本クラスの汎用プライベートメンバーを操作する抽象メソッドを定義するため、抽象としてマークされます。ジェネリックは、ジェネリック型にC#7.3Enum制約を使用します。テストを無事に完了しましたが、期待どおりに機能します。
デビッドA.グレイ

8

これを試して:

public T Get<T>(Stats type ) where T : IConvertible
{
    if (typeof(T) == typeof(int))
    {
        return (T)(object)Convert.ToInt16(PlayerStats[type]);

    }
    if (typeof(T) == typeof(string))
    {

        return (T)(object)PlayerStats[type];
    }
}

これが助けてくれてありがとう、私の必要性は異なります。テストできるように、既存の静的メソッドのモックメソッドを作成しています。このosherove.com/blog/2012/7/8/
Esen

8

実際には、あなただけに変換することができobject、その後にT

T var = (T)(object)42;

bool

public class Program
{
    public static T Foo<T>()
    {
        if(typeof(T) == typeof(bool)) {
            return (T)(object)true;
        }

        return default(T);
    }

    public static void Main()
    {
        bool boolValue = Foo<bool>(); // == true
        string stringValue = Foo<string>(); // == null
    }
}

場合によっては、この動作が望ましいことがあります。たとえば、基本クラスまたはインターフェイスからジェネリックメソッドを実装またはオーバーライドし、Tタイプに基づいていくつかの異なる機能を追加する場合です。


6

@BrokenGlassロジック(Convert.ChangeType)を考慮すると、GUIDタイプはサポートされません。

public T Get<T>(Stats type) where T : IConvertible
{
    return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}

エラー:「System.String」から「System.Guid」へのキャストが無効です。

代わりに、名前空間TypeDescriptor.GetConverterを追加して使用する以下のロジックを使用してくださいSystem.ComponentModel

public T Get<T>(Stats type) where T : IConvertible
{
    (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type])
}

これを読んでください。



0

以下のように簡単にキャストできます。

public T Get<T>(Stats type) where T : IConvertible
{
  if (typeof(T) == typeof(int))
  {
    int t = Convert.ToInt16(PlayerStats[type]);
    return t as T;
  }
 if (typeof(T) == typeof(string))
 {
    string t = PlayerStats[type].ToString();
    return t as T;
 }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.