13

私の質問は、c# と静的メンバーへのアクセス方法に関するものです...まあ、それを説明する方法がよくわかりません (どのような質問が悪いのでしょうか?) サンプル コードをいくつか示します。

Class test<T>{
     int method1(Obj Parameter1){
         //in here I want to do something which I would explain as
         T.TryParse(Parameter1);

         //my problem is that it does not work ... I get an error.
         //just to explain: if I declare test<int> (with type Integer)
         //I want my sample code to call int.TryParse(). If it were String
         //it should have been String.TryParse()
     }
}

回答ありがとうございます (ちなみに、問題は、エラーを発生させずにこの問題を解決するにはどうすればよいかということです)。これはおそらくあなたにとって非常に簡単な質問です!


編集:ご回答いただきありがとうございます!

私は try - キャッチ フレーズが最も洗練されていると思いますが、vb を使用した経験から、それが本当に残念な場合があることを知っています。私はそれを 1 回使用しましたが、プログラムの実行に約 30 分かかりましたが、後で try - catch を回避したため、計算に 2 分しかかかりませんでした。

これが、switch ステートメントを最良の回答として選んだ理由です。コードはより複雑になりますが、一方で、比較的高速で読みやすいと思います。(私はまだもっとエレガントな方法があるべきだと思っています...おそらく私が学ぶ次の言語で)


他の提案があれば、私はまだ待っています(そして喜んで参加します)

4

12 に答える 12

5

問題は、TryParse がインターフェイスまたは基本クラスでどこにも定義されていないため、クラスに渡される型がその関数を持っていると仮定できないことです。なんらかの方法で T を制限できない限り、これに何度も遭遇することになります。

型パラメーターの制約

于 2008-08-21T13:28:29.513 に答える
3

簡単に言えば、できません。

長い答え、あなたはごまかすことができます:

public class Example
{
    internal static class Support
    {
        private delegate bool GenericParser<T>(string s, out T o);
        private static Dictionary<Type, object> parsers =
            MakeStandardParsers();
        private static Dictionary<Type, object> MakeStandardParsers()
        {
            Dictionary<Type, object> d = new Dictionary<Type, object>();
            // You need to add an entry for every type you want to cope with.
            d[typeof(int)] = new GenericParser<int>(int.TryParse);
            d[typeof(long)] = new GenericParser<long>(long.TryParse);
            d[typeof(float)] = new GenericParser<float>(float.TryParse);
            return d;
        }
        public static bool TryParse<T>(string s, out T result)
        {
            return ((GenericParser<T>)parsers[typeof(T)])(s, out result);
        }
    }
    public class Test<T>
    {
        public static T method1(string s)
        {
            T value;
            bool success = Support.TryParse(s, out value);
            return value;
        }
    }
    public static void Main()
    {
        Console.WriteLine(Test<int>.method1("23"));
        Console.WriteLine(Test<float>.method1("23.4"));
        Console.WriteLine(Test<long>.method1("99999999999999"));
        Console.ReadLine();
    }
}

使用したいすべてのタイプのTryParseメソッドのデリゲートを保持する静的辞書を作成しました。次に、辞書を検索して呼び出しを適切なデリゲートに渡すためのジェネリックメソッドを作成しました。すべてのデリゲートは異なる型を持っているので、それらをオブジェクト参照として保存し、それらを取得するときに適切なジェネリック型にキャストし直します。簡単な例として、特定のタイプの辞書にエントリがあるかどうかをチェックするなど、エラーチェックを省略していることに注意してください。

于 2008-08-21T14:08:12.337 に答える
3

特定のクラスまたはインターフェイスのメンバーにアクセスするには、Where キーワードを使用して、メソッドを持つインターフェイスまたは基本クラスを指定する必要があります。

上記のインスタンスでは、TryParse はインターフェイスまたは基本クラスから取得されていないため、上記で実行しようとしていることは不可能です。Convert.ChangeType と try/catch ステートメントを使用するのが最善です。

class test<T>
{
    T Method(object P)
    {
       try {
           return (T)Convert.ChangeType(P, typeof(T));
       } catch(Exception e) {
           return null;
       }
    }
}
于 2008-08-21T13:34:47.923 に答える
2

それを行うもう 1 つの方法は、今回はミックスに反映されます。

static class Parser
{
    public static bool TryParse<TType>( string str, out TType x )
    {
        // Get the type on that TryParse shall be called
        Type objType = typeof( TType );

        // Enumerate the methods of TType
        foreach( MethodInfo mi in objType.GetMethods() )
        {
            if( mi.Name == "TryParse" )
            {
                // We found a TryParse method, check for the 2-parameter-signature
                ParameterInfo[] pi = mi.GetParameters();
                if( pi.Length == 2 ) // Find TryParse( String, TType )
                {
                    // Build a parameter list for the call
                    object[] paramList = new object[2] { str, default( TType ) };

                    // Invoke the static method
                    object ret = objType.InvokeMember( "TryParse", BindingFlags.InvokeMethod, null, null, paramList );

                    // Get the output value from the parameter list
                    x = (TType)paramList[1];
                    return (bool)ret;
                }
            }
        }

        // Maybe we should throw an exception here, because we were unable to find the TryParse
        // method; this is not just a unable-to-parse error.

        x = default( TType );
        return false;
    }
}

次のステップは、実装しようとすることです

public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args );

完全なパラメータ タイプの一致など。

于 2008-08-21T14:46:46.097 に答える
2

これは実際には解決策ではありませんが、特定のシナリオでは良い代替手段になる可能性があります。ジェネリック メソッドに追加のデリゲートを渡すことができます。

言いたいことを明確にするために、例を挙げましょう。T のインスタンスを作成するジェネリック ファクトリ メソッドがあり、通知または追加の初期化のために別のメソッドを呼び出したいとします。

次の単純なクラスを検討してください。

public class Example
{
    // ...

    public static void PostInitCallback(Example example)
    {
        // Do something with the object...
    }
}

そして、次の静的メソッド:

public static T CreateAndInit<T>() where T : new()
{
    var t = new T();
    // Some initialization code...
    return t;
}

したがって、今私たちがしなければならないことは次のとおりです。

var example = CreateAndInit<Example>();
Example.PostInitCallback(example);

ただし、追加のデリゲートを取るようにメソッドを変更できます。

public delegate void PostInitCallback<T>(T t);
public static T CreateAndInit<T>(PostInitCallback<T> callback) where T : new()
{
    var t = new T();
    // Some initialization code...
    callback(t);
    return t;
}

これで、呼び出しを次のように変更できます。

var example = CreateAndInit<Example>(Example.PostInitCallback);

明らかに、これは非常に特定のシナリオでのみ役立ちます。しかし、これは、コンパイル時の安全性が確保され、「ハッキング」がなく、コードが非常に単純であるという意味で、最もクリーンなソリューションです。

于 2012-05-14T20:34:24.747 に答える
1

探していることを正確に行う唯一の方法は、リフレクションを使用して、Tにメソッドが存在するかどうかを確認することです。

もう1つのオプションは、タイプをIConvertibleに制限することによって送信するオブジェクトが変換可能なオブジェクトであることを確認することです(すべてのプリミティブ型はIConvertibleを実装します)。これにより、パラメータを特定のタイプに非常に柔軟に変換できます。

Class test<T>
{
    int method1(IConvertible Parameter1){

        IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));

        T temp = Parameter1.ToType(typeof(T), provider);
    }
}

元々のように代わりに「オブジェクト」タイプを使用して、これを変更することもできます。

Class test<T>
{
    int method1(object Parameter1){

        if(Parameter1 is IConvertible) {

            IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));

            T temp = Parameter1.ToType(typeof(T), provider);

        } else {
           // Do something else
        }
    }
}
于 2008-08-21T14:01:57.110 に答える
1

OKみんな:すべての魚をありがとう。今、あなたの答えと私の研究(特にジェネリック型をプリミティブに制限することに関する記事)で、私はあなたに私の解決策を提示します。

Class a<T>{
    private void checkWetherTypeIsOK()
    {
        if (T is int || T is float //|| ... any other types you want to be allowed){
            return true;
        }
        else {
            throw new exception();
        }
    }
    public static a(){
        ccheckWetherTypeIsOK();
    }
}
于 2008-08-21T14:21:55.143 に答える
1

次のようなことをするつもりですか?

Class test<T>
{
     T method1(object Parameter1){

         if( Parameter1 is T ) 
         {
              T value = (T) Parameter1;
             //do something with value
             return value;
         }
         else
         {
             //Parameter1 is not a T
             return default(T); //or throw exception
         }
     }
}

残念ながら、TryParse パターンは静的であるため、チェックできません。つまり、ジェネリックにはあまり適していません。

于 2008-08-21T13:39:02.297 に答える
0

最良のコード:次のようにTをValueTypeに制限します。

class test1<T> where T: struct

ここでの「構造体」とは、値型を意味します。文字列はクラスであり、値型ではありません。int、float、列挙型はすべて値型です。

ところで、コンパイラは、次の例のように、静的メソッドの呼び出しや「型パラメータ」の静的メンバーへのアクセスを受け入れません。これはコンパイルされません:(

class MyStatic { public static int MyValue=0; }
class Test<T> where T: MyStatic
{
    public void TheTest() { T.MyValue++; }
}

=>エラー1'T'は'タイプパラメータ'であり、指定されたコンテキストでは無効です

SL。

于 2009-07-16T16:20:15.940 に答える
0

ジェネリック型をプリミティブに制限することに関する私の以前の投稿を読みたいと思うかもしれません。これにより、ジェネリックに渡すことができる型を制限するためのいくつかのポインターが得られる場合があります ( TypeParseは明らかにプリミティブのセット数でしか使用できないため ( string.TryParseは明らかに例外であり、意味がありません)。

型のハンドルが増えたら、それを解析しようとすることができます。(正しいTryParseを呼び出すために)少し醜いスイッチが必要になるかもしれませんが、目的の機能を実現できると思います。

上記のいずれかについてさらに説明する必要がある場合は、お尋ねください:)

于 2008-08-21T13:35:06.003 に答える
0

あなたはおそらくそれを行うことはできません。

まず第一に、可能であれば、T のより厳密な境界が必要になるため、タイプチェッカーは、T のすべての可能な置換が実際に TryParse と呼ばれる静的メソッドを持っていることを確認できます。

于 2008-08-21T13:28:49.683 に答える
-1

それは静的がどのように機能するかではありません。statics は、たとえそれらがたくさんの型に分散されていたとしても、Global クラスの一種と考える必要があります。私の推奨は、必要な静的メソッドにアクセスできる T インスタンス内のプロパティにすることです。

また、T は何かの実際のインスタンスであり、他のインスタンスと同様に、インスタンス化された値を介してその型の静的にアクセスすることはできません。以下は、何をすべきかの例です。

class a {
    static StaticMethod1 ()
    virtual Method1 ()
}

class b : a {
    override Method1 () return StaticMethod1()
}

class c : a {
    override Method1 () return "XYZ"
}

class generic<T> 
    where T : a {
    void DoSomething () T.Method1()
}
于 2008-08-21T13:30:18.887 に答える