문제

프리미티브에 전달되는 유형을 적용/제한하는 방법이 있습니까? (부울, 정수, 문자열 등)

이제 일반 유형 매개변수를 다음을 통해 유형 또는 인터페이스 구현으로 제한할 수 있다는 것을 알고 있습니다. 어디 절.그러나 이는 모두 공통 기반을 갖지 않기 때문에 AFAIK(기본 요소에 대한 법안)에 맞지 않습니다. 물체 누가 말하기 전에!:피).

그래서 현재 내 생각은 그냥 이를 악물고 큰 일을 하려는 것입니다. 스위치 진술하고 던지기 인수예외 실패에..


편집 1:

다시 한번 확인하기 위해:

코드 정의는 다음과 같아야 합니다.

public class MyClass<GenericType> ....

그리고 인스턴스화:

MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

편집 2

@Jon Limjap - 좋은 지적이군요. 이미 고려하고 있던 사항이군요..유형이 값 유형인지 참조 유형인지 확인하는 데 사용할 수 있는 일반적인 방법이 있다고 확신합니다.

이는 처리하고 싶지 않은 많은 개체를 즉시 제거하는 데 유용할 수 있습니다(그러나 다음과 같이 사용되는 구조체에 대해 걱정해야 합니다). 크기 )..흥미로운 문제 아닌가요?:)

여기있어:

where T : struct

에서 가져옴 MSDN.


궁금해..확장 메서드를 사용하여 .NET 3.x에서 이 작업을 수행할 수 있습니까?인터페이스를 생성하고 확장 메서드에서 인터페이스를 구현합니다(아마도 약간 뚱뚱한 스위치보다 더 깔끔할 것입니다).또한 나중에 경량 사용자 정의 유형으로 확장해야 하는 경우 기본 코드를 변경할 필요 없이 동일한 인터페이스를 구현할 수도 있습니다.

여러분은 어떻게 생각하시나요?

슬픈 소식은 제가 Framework 2에서 작업하고 있다는 것입니다!!:디


편집 3

다음은 매우 간단했습니다. 존 림잡스 포인터..너무 단순해서 울고 싶을 정도인데, 코드가 매력처럼 작동해서 좋아요!

그래서 제가 한 일은 다음과 같습니다(웃으실 겁니다!).

일반 클래스에 추가된 코드

bool TypeValid()
{
    // Get the TypeCode from the Primitive Type
    TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));

    // All of the TypeCode Enumeration refer Primitive Types
    // with the exception of Object and Empty (Null).
    // Since I am willing to allow Null Types (at this time)
    // all we need to check for is Object!
    switch (code)
    {
        case TypeCode.Object:
            return false;
        default:
            return true;
    }
}

그런 다음 유형을 확인하고 예외를 발생시키는 약간의 유틸리티 메서드,

private void EnforcePrimitiveType()
{
    if (!TypeValid())
        throw new InvalidOperationException(
            "Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name + 
            "' - this Class is Designed to Work with Primitive Data Types Only.");
}

그런 다음 수행해야 할 모든 작업은 전화하는 것입니다. EnforcePrimitiveType() 클래스 생성자에서.작업 완료!:-)

유일한 단점은 디자인 타임이 아닌 런타임에만 예외가 발생한다는 것입니다.그러나 그것은 큰 문제가 아니며 다음과 같은 유틸리티를 사용하여 선택할 수 있습니다. FxCop (우리는 직장에서 사용하지 않습니다).

이에 대해 Jon Limjap에게 특별히 감사드립니다!

도움이 되었습니까?

해결책

기본 요소는 TypeCode 열거:

아마도 객체에 다음이 포함되어 있는지 알아내는 방법이 있을 것입니다. TypeCode enum 특정 객체로 캐스팅하거나 호출할 필요 없이 GetType() 또는 typeof()?

업데이트 바로 코 바로 밑에 있었어요.코드 샘플은 다음을 보여줍니다.

static void WriteObjectInfo(object testObject)
{
    TypeCode    typeCode = Type.GetTypeCode( testObject.GetType() );

    switch( typeCode )
    {
        case TypeCode.Boolean:
            Console.WriteLine("Boolean: {0}", testObject);
            break;

        case TypeCode.Double:
            Console.WriteLine("Double: {0}", testObject);
            break;

        default:
            Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
            break;
        }
    }
}

여전히 보기 흉한 스위치입니다.하지만 시작하기 좋은 곳이에요!

다른 팁

public class Class1<GenericType> where GenericType : struct
{
}

이게 그 역할을 하는 것 같았어요..

@Lars가 이미 말한 내용은 다음과 같습니다.

//Force T to be a value (primitive) type.
public class Class1<T> where T: struct

//Force T to be a reference type.
public class Class1<T> where T: class

//Force T to be a parameterless constructor.
public class Class1<T> where T: new()

모두 .NET 2, 3 및 3.5에서 작동합니다.

(요청한 MyClass 생성자 대신) 팩토리 메소드 사용을 허용할 수 있다면 언제든지 다음과 같이 할 수 있습니다.

class MyClass<T>
{
  private readonly T _value;

  private MyClass(T value) { _value = value; }

  public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
  public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
  // etc for all the primitive types, or whatever other fixed set of types you are concerned about
}

여기서 문제는 다음을 입력해야 한다는 것입니다. MyClass<AnyTypeItDoesntMatter>.FromInt32, 짜증나네요.생성자의 비공개성을 유지하려는 경우 이 문제를 해결할 수 있는 좋은 방법은 없지만 다음과 같은 몇 가지 해결 방법이 있습니다.

  • 추상 클래스 만들기 MyClass.만들다 MyClass<T> ~로부터 상속받다 MyClass 그리고 그 안에 중첩시키세요 MyClass.정적 메소드를 다음으로 이동하십시오. MyClass.이렇게 하면 액세스해야 하는 비용으로 모든 가시성이 작동합니다. MyClass<T> ~처럼 MyClass.MyClass<T>.
  • 사용 MyClass<T> 주어진대로.정적 클래스 만들기 MyClass 이는 정적 메소드를 호출합니다. MyClass<T> 사용하여 MyClass<AnyTypeItDoesntMatter> (아마도 단지 웃기 위해 매번 적절한 유형을 사용했을 것입니다).
  • (더 쉽지만 확실히 이상함) 추상 유형 만들기 MyClass 상속받은 것 MyClass<AnyTypeItDoesntMatter>.(구체적으로 말하자면 MyClass<int>.) 파생 클래스의 이름을 통해 기본 클래스에 정의된 정적 메서드를 호출할 수 있으므로 이제 다음을 사용할 수 있습니다. MyClass.FromString.

이렇게 하면 더 많은 쓰기 비용을 들여 정적 검사를 수행할 수 있습니다.

동적 검사에 만족한다면 위의 TypeCode 솔루션을 약간 변형하여 사용하겠습니다.

@롭, Enum의 것들은 빠져나갈 것이다 TypeValid 그대로 기능하다 TypeCode ~이다 Integer.확인하는 기능도 업데이트했습니다. Enum.

Private Function TypeValid() As Boolean
    Dim g As Type = GetType(T)
    Dim code As TypeCode = Type.GetTypeCode(g)

    ' All of the TypeCode Enumeration refer Primitive Types
    ' with the exception of Object and Empty (Nothing).
    ' Note: must also catch Enum as its type is Integer.
    Select Case code
        Case TypeCode.Object
            Return False
        Case Else
            ' Enum's TypeCode is Integer, so check BaseType
            If g.BaseType Is GetType(System.Enum) Then
                Return False
            Else
                Return True
            End If
    End Select
End Function

다음을 단순화할 수 있습니다. EnforcePrimitiveType 을 사용하여 방법 typeof(PrimitiveDataType).IsPrimitive 재산.뭔가 빠졌나요?

사용자 정의 사용 FxCop 바람직하지 않은 사용을 표시하는 규칙 MyClass<>.

비슷한 문제를 겪고 있는데, 여러분은 어떻게 느끼셨는지 궁금합니다. I변환 가능한 인터페이스.이는 요청자가 요구하는 것을 허용하며 자체 구현으로 확장할 수 있습니다.

예:

    public class MyClass<TKey>
    where TKey : IConvertible
{
    // class intentionally abbreviated
}

나는 이것을 해결책으로 생각하고 있지만 제안된 것 중 많은 부분이 내가 선택한 것의 일부이기도 했습니다.

그러나 내 관심사는 귀하의 클래스를 사용하는 잠재적인 개발자가 오해를 불러일으킬 수 있다는 것입니다.

건배 - 감사합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top