質問

プリミティブに渡される型を強制/制限する方法はありますか? (ブール、整数、文字列など)

これで、ジェネリック型パラメーターを型またはインターフェイスの実装に制限できることがわかりました。 どこ 句。ただし、これはプリミティブの要件には当てはまりません(私の知る限り)。 物体 誰かが言う前に!:P)。

だから、今の私の考えは、歯を食いしばって大きなことをすることです。 スイッチ ステートメントをスローします 引数例外 失敗について。。


編集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 で作業しています!!:D


編集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() クラスのコンストラクター内で。仕事は終わりました!:-)

唯一の欠点は、設計時ではなく、(当然のことですが) 実行時にのみ例外をスローすることです。しかし、それは大したことではなく、次のようなユーティリティで実現できるでしょう。 FXコップ (仕事では使いません)。

この件については 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 そのまま機能する TypeCodeInteger. 。もチェックする機能を更新しました 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 財産。何かが足りないのでしょうか?

カスタムを使用する FXコップ の望ましくない使用を警告するルール MyClass<>.

同じような課題を抱えているので、皆さんはどう感じたか疑問に思いました。 I変換可能なインターフェース. 。リクエスターが要求するものを許可し、独自の実装で拡張できます。

例:

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

私はこれを解決策として考えていますが、提案されたものの多くは私の選択の一部でもありました。

しかし、私の懸念は、あなたのクラスを使用する潜在的な開発者にとって誤解を招くものではないかということです。

乾杯 - そしてありがとう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top