C#中的泛型&访问T的静态成员
我的问题涉及到如何访问静态成员...好吧,我真的不知道如何解释它(最常见的问题是,不是吗?)我将仅提供一些示例代码:
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 catch短语是最优雅的短语,但根据我在vb的经验,我知道它确实可以让我们感到不愉快。我用了一次,运行一个程序大约要花30分钟,后来又花了2分钟来计算,只是因为我避免了try catch。
这就是为什么我选择swich语句作为最佳答案的原因。它使代码更复杂,但另一方面,我认为它相对较快且相对易于阅读。 (尽管我仍然认为应该有一种更优雅的方法……也许用我学习的另一种语言:P)
虽然如果我们还有其他建议,我仍在等待(并愿意参加)
解决方案
回答
问题在于TryParse没有在任何地方的接口或者基类上定义,因此我们不能假设传递给类的类型将具有该功能。除非我们能以某种方式禁忌T,否则我们会遇到很多麻烦。
类型参数的约束
回答
你可能做不到。
首先,如果可能的话,我们需要对T设置更严格的限制,以便类型检查器可以确保对T的所有可能替代实际上都有一个称为TryParse的静态方法。
回答
静态不是这样工作的。我们必须将静态类视为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() }
回答
要访问特定类或者接口的成员,我们需要使用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; } } }
回答
我们可能需要阅读我以前的文章,即将泛型类型限制为基元。这可能会为我们提供一些指针,以限制可以传递给泛型的类型(因为TypeParse显然仅可用于一定数量的基元(string.TryParse显然是例外,这没有意义)。
一旦对类型有了更多的了解,就可以尝试解析它。我们可能需要在其中添加一些难看的开关(以调用正确的TryParse),但是我认为我们可以实现所需的功能。
如果我们需要我进一步解释以上任何一项,请询问:)
回答
我们是要执行以下操作吗?
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 } } }
回答
简短的答案,你不能。
长答案,你可以作弊:
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方法的委托。然后,我编写了一个通用方法来查找字典并将调用传递给适当的委托。由于每个委托都有不同的类型,因此我只将它们存储为对象引用,并在检索它们时将它们强制转换回适当的通用类型。注意,为简单起见,我省略了错误检查,例如检查字典中是否有给定类型的条目。
回答
好的,伙计们:感谢所有的鱼。现在,有了答案和我的研究(尤其是有关将泛型类型限制为基元的文章),我将向我们介绍我的解决方案。
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(); } }
回答
这是另一种实现方式,这一次在组合中有所体现:
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 );
具有完整的参数类型匹配等
回答
最佳代码:通过以下方式将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。