سؤال

سؤالي المخاوف 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()
     }
}

شكرا لكم على إجاباتك (بالمناسبة السؤال هو:كيف يمكنني حل هذه المشكلة دون الحصول على خطأ).هذا على الأرجح تماما مسألة سهلة بالنسبة لك!

شكرا يا نيكلاس


تحرير:شكرا لكم جميعا على إجاباتك!

على الرغم من أنني أعتقد حاول اللحاق العبارة هي الأكثر أناقة ، أنا أعرف من تجربتي مع vb أنه يمكن أن يكون حقا مشكلة.أنا استخدم مرة واحدة واستغرق حوالي 30 دقيقة لتشغيل البرنامج ، والتي في وقت لاحق أخذت فقط 2 دقيقة لحساب فقط لأنني تجنب محاولة اللحاق.

هذا هو السبب في أنني اخترت swich بيان كأفضل إجابة.يجعل رمز أكثر تعقيدا ولكن من ناحية أخرى أتصور أن يكون نسبيا وسريعة نسبيا سهلة القراءة.(على الرغم من أنني ما زلت أعتقد يجب أن يكون هناك طريقة أكثر أناقة ...ربما في القادم لغة أتعلم :P )


على الرغم من إذا كان لديك اقتراح آخر أنا لا تزال تنتظر (و على استعداد للمشاركة)

هل كانت مفيدة؟

المحلول

أكثر من طريقة للقيام بذلك, هذا بعض الوقت للتأمل في مزيج:

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 );

مع كامل المعلمة نوع مطابقة الخ.

نصائح أخرى

المشكلة هي أن TryParse ليست محددة على واجهة أو قاعدة الطبقة في أي مكان إذا كنت لا يمكن أن تجعل افتراض أن هذا النوع مرت في الفئة الخاصة بك وسوف يكون ذلك وظيفة.إلا إذا كنت يمكن أن contrain T في بعض الطريق, سوف تصل إلى هذا الكثير.

القيود على نوع المعلمات

الجواب القصير, لا يمكنك.

الجواب طويل ، يمكنك الغش:

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 طريقة كل نوع قد ترغب في استخدام.ثم كتب عامة طريقة للبحث عن القاموس و تمر على الدعوة إلى المناسبة مندوب.لأن كل مندوب لديه نوع مختلف, أنا فقط تخزينها وجوه المراجع يلقي لهم العودة إلى مناسبة عامة النوع عندما استردادها.ملاحظة أنه من أجل مثال بسيط كنت قد حذفت خطأ التحقق ، مثل أن تحقق ما إذا كان علينا الدخول في قاموس نوع معين.

للوصول إلى عضو من فئة معينة أو واجهة تحتاج إلى استخدام حيث الكلمة و تحديد واجهة أو قاعدة فئة من طريقة.

في المثال أعلاه TryParse لا يأتي من واجهة أو قاعدة الطبقة ، إذا ما كنت تحاول القيام به أعلاه هو غير ممكن.الأفضل استخدام تحويل.ChangeType و حاول/catch.

class test<T>
{
    T Method(object P)
    {
       try {
           return (T)Convert.ChangeType(P, typeof(T));
       } catch(Exception e) {
           return null;
       }
    }
}

يعني أن تفعل شيئا من هذا القبيل:

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 نمط كما هو ثابت - والتي للأسف يعني أنه ليست مناسبة بشكل خاص إلى الأدوية.

الطريقة الوحيدة للقيام بالضبط ما كنت تبحث عن استخدام انعكاس للتحقق إذا كان الأسلوب موجود T.

وثمة خيار آخر هو التأكد من أن الكائن الذي أرسل سيارة الكائن من خلال تقييد نوع 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
        }
    }
}

طيب الرجال:شكرا على كل السمك.الآن مع إجابات بحثي (وخاصة المادة على الحد عامة أنواع الأوليات) سوف نقدم لكم الحل.

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();
    }
}

هذا ليس حلا ، ولكن في بعض الحالات يمكن أن يكون بديلا جيدا:يمكننا تمرير إضافية مندوب عامة الأسلوب.

توضيح ما أعني دعونا نستخدم هذا المثال.دعونا نقول لدينا بعض العامة مصنع الطريقة التي يجب إنشاء مثيل 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);

من الواضح أن هذا هو فقط مفيدة جدا في سيناريوهات محددة.ولكن هذا هو أنظف الحل بمعنى أن نحصل على وقت الترجمة السلامة, لا يوجد "القرصنة" تشارك و رمز بسيط الميت.

ربما كنت غير قادر على القيام بذلك.

أولا إذا كان ينبغي أن يكون من الممكن أنك سوف تحتاج أكثر إحكاما لا بد على ر حتى typechecker يمكن أن تكون على يقين من أن كل شيء ممكن بدائل تي في الواقع أسلوب ثابت يسمى TryParse.

قد ترغب في قراءة مشاركتي السابقة على الحد عامة أنواع الأوليات.وهذا قد تعطيك بعض المؤشرات في الحد من النوع الذي يمكن أن تنتقل إلى عام (منذ TypeParse من الواضح متاح فقط إلى تعيين عدد من الأوليات ( السلسلة.TryParse ومن الواضح أن الاستثناء الذي لا معنى له).

مرة واحدة لديك أكثر من مؤشر على نوع يمكنك ثم العمل على محاولة تحليل ذلك.قد تحتاج قليلا من قبيح التبديل في (الدعوة الصحيحة TryParse ) ولكن أعتقد أنك يمكن أن يحقق الوظيفة المطلوبة.

إذا كنت في حاجة لي أن أشرح أي من أعلاه أيضا ، ثم فضلك اطلب :)

أفضل كود:تقييد T ValueType هذه الطريقة:

class test1<T> where T: struct

و "البنية" هنا يعني نوع القيمة.السلسلة هي فئة لا قيمة نوع.int, float, Enums جميع أنواع قيمة.

راجع للشغل المترجم لا يقبل استدعاء أساليب ثابتة أو الوصول إلى أعضاء ثابتة على نوع المعلمات' كما في المثال التالي الذي لن ترجمة :(

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

=> خطأ 1 'T' هو 'نوع المعلمة التي لا تصح في هذا السياق

SL.

هذا ليس كيف احصائيات العمل.عليك أن تفكر من السكون كنوع من الدرجة العالمية حتى لو كانت تنتشر عبر مجموعة كاملة من الأنواع.توصيتي هي أن تجعل الإقامة داخل 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()
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top