암시 적으로 '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.