代码之家  ›  专栏  ›  技术社区  ›  niklasfi Rahul Tripathi

C中的泛型和访问T的静态成员

  •  13
  • niklasfi Rahul Tripathi  · 技术社区  · 18 年前

    我的问题是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()
         }
    }
    

    所以谢谢你们的回答(顺便问一下,问题是:我如何在不出错的情况下解决这个问题)。这个问题对你来说可能很简单!

    谢谢,Niklas


    编辑:谢谢大家的回答!

    虽然我认为试着抓住短语是最优雅的,但我从我对vb的经验中知道,它确实是一个令人讨厌的词。我用过一次,运行一个程序大约花了30分钟,后来只花了2分钟计算,因为我避免了尝试捕获。

    这就是为什么我选择瑞士话作为最佳答案的原因。它使代码更加复杂,但另一方面,我认为它相对较快,也相对容易阅读。(尽管我仍然认为应该有一种更优雅的方式……也许在我学习的下一种语言中:p)


    不过,如果你有其他建议,我仍在等待(并愿意参与)

    12 回复  |  直到 12 年前
        1
  •  2
  •   Timbo    18 年前

    另一种方法是,这次在组合中进行一些思考:

    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
  •  5
  •   Greg Hurlman    18 年前

    问题是,任何地方都没有在接口或基类上定义typarse,因此不能假定传递到类中的类型将具有该函数。除非你能以某种方式克服困难,否则你会遇到很多困难。

    Constraints on Type Parameters

        3
  •  3
  •   Weeble    18 年前

    简短的回答,你不能。

    答案很长,你可以作弊:

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

    我制作了一个静态字典,其中包含我可能想要使用的每种类型的台盼方法的委托。然后我编写了一个通用方法来查找字典并将调用传递给适当的委托。因为每个委托都有不同的类型,所以我只将它们存储为对象引用,并在检索它们时将它们转换回适当的泛型类型。请注意,为了一个简单的示例,我省略了错误检查,例如检查给定类型的字典中是否有条目。

        4
  •  3
  •   samjudson    12 年前

    要访问特定类或接口的成员,需要使用Where关键字并指定具有该方法的接口或基类。

    在上面的实例中,typarse不是来自接口或基类,因此您试图在上面做的事情是不可能的。最好只使用convert.changetype和try/catch语句。

    class test<T>
    {
        T Method(object P)
        {
           try {
               return (T)Convert.ChangeType(P, typeof(T));
           } catch(Exception e) {
               return null;
           }
        }
    }
    
        5
  •  2
  •   Community Mohan Dere    9 年前

    好的,伙计们:谢谢你们的鱼。现在就来看看你的答案和我的研究(尤其是关于 limiting generic types to primitives )我将向你介绍我的解决方案。

    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();
        }
    }
    
        6
  •  1
  •   Keith    18 年前

    你想这样做吗?

    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
             }
         }
    }
    

    不幸的是,你不能检查胰蛋白酶模式,因为它是静态的——这很不幸地意味着它不特别适合于仿制药。

        7
  •  1
  •   Dan Herbert    18 年前

    唯一的方法就是使用反射来检查是否存在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
            }
        }
    }
    
        8
  •  1
  •   Amir Abiri    14 年前

    这不是一个真正的解决方案,但在某些情况下,它可能是一个很好的替代方案:我们可以向泛型方法传递一个额外的委托。

    为了阐明我的意思,让我们用一个例子。假设我们有一些通用的工厂方法,它应该创建一个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);
    

    显然,这只在非常具体的场景中有用。但从我们获得编译时安全性的角度来看,这是最干净的解决方案,不涉及“黑客攻击”,而且代码非常简单。

        9
  •  0
  •   svrist    18 年前

    你可能做不到。

    首先,如果可能的话,您需要在t上有一个更严格的界限,这样类型检查器可以确保所有可能的t替换实际上都有一个名为typarse的静态方法。

        10
  •  0
  •   Community Mohan Dere    9 年前

    你可能想在上阅读我以前的文章 limiting generic types to primitives . 这可能会给您一些指针来限制可以传递给泛型的类型(因为 类型解析 显然只对一组基元可用( 特里帕斯 显然是例外,这是不合理的)。

    一旦对类型有了更多的句柄,就可以尝试解析它了。你可能需要一个难看的开关 三分法 )但我认为您可以实现所需的功能。

    如果您需要我进一步解释上述任何一项,请问:)

        11
  •  0
  •   Softlion    17 年前

    最佳代码:将t限制为valuetype,方法如下:

    class test1<T> where T: struct
    

    这里的“struct”表示值类型。 字符串是类,而不是值类型。 int、float和enum都是值类型。

    btw编译器不接受调用静态方法或访问“类型参数”上的静态成员,如以下示例中不会编译的那样:(

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

    =>错误1“t”是“类型参数”,在给定上下文中无效

    SL。

        12
  •  -1
  •   Nick Berardi    18 年前

    静力学不是这样工作的。您必须将静态看作是全局类中的一种,即使它们分布在一系列类型中。我的建议是使它成为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()
    }
    
    推荐文章