암시 적으로 'Int'형식을 'T'로 변환 할 수 없습니다.


90

전화를 걸 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 일 수만 있다면 처음부터 이런 식으로 코드를 작성하지 마십시오. int를 반환하는 메서드와 문자열을 반환하는 메서드를 작성합니다.


1
자동차가 IConvertible을 구현하는 Get <Car>는 파손을 유발합니다. 누군가가 당신이 제네릭 메서드를 가지고 있다는 것을 알게되면 그들은 IConvertible을 구현하는 모든 것을 전달할 수 있다고 가정합니다.
Tjaart

10
@Eric. XML 태그에 저장된 배열을 구문 분석해야하는 상황이 있습니다. 문제는 XML 문서가 따르는 사양 (제 경우에는 COLLADA)이 이러한 배열이 될 수 있다고 말합니다. float, int 및 bool뿐만 아니라 일부 사용자 정의 유형도 있습니다. 그러나 float [] (array-tags는 이름에 저장된 데이터 유형을 포함합니다 : float_array는 부동 소수점을 저장함)을 얻는 경우 문자열을 다음의 배열로 구문 분석해야합니다. 일부 IFormatProvider를 사용해야합니다). 분명히 "T.Parse (...)"를 사용할 수 없습니다. 따라서 일부 경우에 이러한 전환을 사용해야합니다.
rbaleksandar 2013

1
이 대답은 당신을 토끼 구멍에서 벗어나게 할 것입니다. 를위한 일반 함수를 만들고 싶었는데 int, int?, bool, bool?, string불가능 해 보였습니다.
Jess

이렇게하면 일반 열거 형에 대한 스위치가 실용적입니다.
David A. Gray

1
나는 이것을 답으로 사용하고 싶지 않았습니다. 그러나 그는 옳다. 유형을 확인하고 특정 유형이면 속성을 설정하고 싶었습니다. 해결책은 강력한 형식의 매개 변수를 사용하는 메서드를 만드는 것이 었습니다.
Matt Dawdy

139

Convert.ChangeType()사용자 지정 코드 대신 사용할 수 있어야합니다 .

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

20
어떻습니까return (T)(object)PlayerStats[type];
maxp

11
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;널 검사가 필요하지 않기 때문입니다.
BoltClock

위의 내용은 나를 위해 컴파일되지 않습니다. T는 컴파일 할 "as"에 대한 참조 유형이어야합니다.
Robert Schmidt

9

ChangeType아마도 최선의 선택 일 것입니다. 내 솔루션은 약간의 try catch 논리를 사용하여 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.3 Enum 제약 조건을 사용합니다. 방금 테스트를 성공적으로 마쳤으며 원하는대로 작동합니다.
David A. Gray

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.