Дженерики в c# и доступе к статическим членам T

Вы можете найти полезный модуль fileinput . Он предназначен именно для этой проблемы.

13
задан BIBD 26 November 2008 в 19:19
поделиться

11 ответов

Еще один способ сделать это, на этот раз некоторое отражение в соединении:

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

С полным типом параметра, соответствующим и т.д.

2
ответ дан 2 December 2019 в 00:04
поделиться

Это не то, как работают помехи. Необходимо думать о помехах как о виде в Глобальном классе, даже если они, распространены через целый набор типов. Моя рекомендация состоит в том, чтобы сделать это свойством в экземпляре 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()
}
-1
ответ дан 2 December 2019 в 00:04
поделиться

Можно хотеть прочитать мое предыдущее сообщение на ограничивающие универсальные типы к примитивам . Это может дать Вам некоторые подсказки в ограничении типа, который может быть передан дженерику (так как TypeParse очевидно только доступен количеству набора примитивов ( строка. TryParse, очевидно, являющийся исключением, которое не имеет смысла).

, Как только у Вас есть больше дескриптора на типе, можно тогда работать над попыткой проанализировать его. Вам, возможно, понадобится что-то вроде ужасного переключателя там (для вызова корректного TryParse), но я думаю, что можно достигнуть желаемой функциональности.

при необходимости во мне для объяснения какого-либо вышеупомянутого далее, затем, спросите:)

0
ответ дан 2 December 2019 в 00:04
поделиться

Хорошо парни: Спасибо за всю рыбу. Теперь с Вашими ответами и моим исследованием (особенно статья о ограничивающие универсальные типы к примитивам ) я представлю Вас мое решение.

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();
    }
}
1
ответ дан 2 December 2019 в 00:04
поделиться

Вы, вероятно, наклон делаете это.

, В первую очередь, если бы должно быть возможно, что Вам было бы нужно более трудное, привязал T, таким образом, typechecker мог бы быть уверен, что все возможные замены на T на самом деле имели статический метод под названием TryParse.

0
ответ дан 2 December 2019 в 00:04
поделиться

Сделайте Вы означаете делать что-то вроде этого:

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, поскольку это статично - который, к сожалению, означает, что это не особенно хорошо подходит для дженериков.

1
ответ дан 2 December 2019 в 00:04
поделиться

Получить доступ к члену определенного класса или соединить интерфейсом с Вами должны использовать, Где ключевое слово и определяет интерфейсный или базовый класс, который имеет метод.

В вышеупомянутом экземпляре TryParse не происходит из интерфейсного или базового класса, поэтому что Вы пытаетесь сделать выше, не возможно. Лучше всего просто используйте, Преобразовывают. ChangeType и оператор попытки/выгоды.

class test<T>
{
    T Method(object P)
    {
       try {
           return (T)Convert.ChangeType(P, typeof(T));
       } catch(Exception e) {
           return null;
       }
    }
}
3
ответ дан 2 December 2019 в 00:04
поделиться

Короткий ответ, Вы не можете.

ответ Long, можно обмануть:

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 каждого типа, который я мог бы хотеть использовать. Я тогда записал общий метод искать словарь и передать вызов соответствующему делегату. Так как у каждого делегата есть другой тип, я просто храню их как ссылки на объект и бросаю их назад к соответствующему универсальному типу, когда я получаю их. Обратите внимание, что ради простого примера я опустил проверку ошибок, например, проверить, есть ли у нас запись в словаре для данного типа.

3
ответ дан 2 December 2019 в 00:04
поделиться

Единственный способ сделать точно, что Вы ищете, состоял бы в том, чтобы использовать отражение, чтобы проверить, существует ли метод для 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
        }
    }
}
1
ответ дан 2 December 2019 в 00:04
поделиться

Проблема состоит в том, что TryParse не определяется на интерфейсном или базовом классе нигде, таким образом, Вы не можете сделать предположение, что тип, переданный в Ваш класс, будет иметь ту функцию. Если Вы не сможете ограничить T в некотором роде, Вы столкнетесь с этим много.

Ограничения на Параметры Типа

5
ответ дан 2 December 2019 в 00:04
поделиться

Лучший код: ограничить 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.

0
ответ дан 2 December 2019 в 00:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: