71

プリミティブに渡される型を強制/制限する方法はありますか? (bool、int、string など)

これで、ジェネリック型パラメーターをwhere句を介して型またはインターフェイスの実装に制限できることがわかりました。ただし、これはプリミティブ (AFAIK) の法案には適合しません。なぜなら、それらはすべて共通の基盤を持っているわけではないからです (誰かが言う前のオブジェクトは別として!:P)。

したがって、私の現在の考えは、歯を食いしばって大きなswitchステートメントを実行し、失敗時にArgumentExceptionをスローすることです。


編集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 - 良い点、そして私がすでに考えていたこと。型が値型か参照型かを判断するために使用できる汎用メソッドがあると確信しています。

これは、処理したくない多くのオブジェクトを即座に削除するのに役立ちます (ただし、Sizeなどの使用される構造体について心配する必要があります)。興味深い問題はありませんか?:)

ここにあります:

where T: struct

MSDNから取得。


私は興味がある。これは、拡張メソッドを使用して .NET 3.x で実行できますか? インターフェイスを作成し、そのインターフェイスを拡張メソッドに実装します (これはおそらく少し太ったスイッチよりもクリーンです)。さらに、後で軽量のカスタム型に拡張する必要がある場合は、基本コードを変更する必要なく、同じインターフェイスを実装することもできます。

皆さんはどう思いますか?

悲しいニュースは、私は Framework 2 で作業していることです!! :D


編集3

これは、Jon Limjaps Pointerに続くとてもシンプルなものでした。とてもシンプルで泣きそうになりましたが、コードが魔法のように機能するので素晴らしいです!

それで、これが私がやったことです(あなたは笑うでしょう!):

ジェネリック クラスに追加されたコード

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 に感謝します!

4

8 に答える 8

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

これは仕事をしているように見えた..

于 2008-08-12T15:11:58.990 に答える
40

プリミティブはTypeCode列挙で指定されているようです:

TypeCode enumおそらく、オブジェクトを特定のオブジェクトにキャストしたり、GetType()or 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;
        }
    }
}

それはまだ醜いスイッチです。しかし、それは始めるのに良い場所です!

于 2008-08-12T15:21:44.010 に答える
22

@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()

すべて.NET2、3、および3.5で動作します。

于 2008-08-12T15:43:37.260 に答える
4

(要求したコンストラクター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。これは面倒です。コンストラクターのプライベート性を維持したい場合、これを回避する良い方法はありませんが、いくつかの回避策があります。

  • 抽象クラスを作成しますMyClassMyClass<T>から継承し、内にネストMyClass しますMyClass。静的メソッドをに移動しますMyClassMyClass<T>これにより、としてアクセスする必要がありますが、すべての可視性が機能しますMyClass.MyClass<T>
  • 与えられたとおりに使用MyClass<T>します。使用時MyClassに静的メソッドを呼び出す静的クラスを作成します(おそらく、笑いのためだけに、毎回適切な型を使用します)。MyClass<T>MyClass<AnyTypeItDoesntMatter>
  • (簡単ですが、確かに奇妙です)MyClass から継承する抽象型を作成しMyClass<AnyTypeItDoesntMatter>ます。(具体的には、たとえばMyClass<int>。)派生クラスの名前を使用して基本クラスで定義された静的メソッドを呼び出すことができるため、を使用できるようになりMyClass.FromStringました。

これにより、書き込みが増える代わりに静的チェックが可能になります。

動的チェックに満足している場合は、上記のTypeCodeソリューションのバリエーションを使用します。

于 2008-09-16T05:52:05.993 に答える
2

EnforcePrimitiveTypeプロパティを使用してメソッドを簡略化できtypeof(PrimitiveDataType).IsPrimitiveます。何か不足していますか?

于 2008-10-19T22:38:42.603 に答える
2

の望ましくない使用法にフラグを立てるカスタムFxCopMyClass<>ルールを使用します。

于 2008-08-12T15:21:05.433 に答える
2

同様の課題を抱えていたので、皆さんがIConvertible インターフェイスについてどのように感じているのか知りたいと思っていました。リクエスタが必要とするものを許可し、独自の実装で拡張できます。

例:

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

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

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

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

于 2012-07-27T14:47:55.360 に答える