我的问题与c#和如何访问静态成员有关...好吧,我真的不知道如何解释它(对问题不利的是什么?),我仅向您提供一些示例代码:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 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。
这就是为什么我选择switch语句作为最佳答案的原因。它使代码更加复杂,但另一方面,我认为它相对较快且相对易于阅读。 (尽管我仍然认为应该有一种更优雅的方法……也许是我学习的另一种语言)
 
虽然如果您还有其他建议,我仍在等待(并愿意参加)
问题是TryParse不在任何地方的接口或基类上定义,因此您不能假设传递给您的类的类型将具有该功能。除非您能以某种方式禁忌T,否则您会遇到很多麻烦。
类型参数的约束
简短的答案,你不能。
长答案,你可以作弊:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 
 | 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方法的委托。然后,我编写了一个通用方法来查找字典并将调用传递给适当的委托。由于每个委托都有不同的类型,因此我只将它们存储为对象引用,并在检索它们时将它们转换回适当的通用类型。请注意,为简单起见,我省略了错误检查,例如检查字典中是否有给定类型的条目。
要访问特定类或接口的成员,您需要使用Where关键字并指定具有该方法的接口或基类。
在上面的实例中,TryParse不是来自接口或基类,因此您上面所做的尝试是不可能的。最好只使用Convert.ChangeType和try / catch语句。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | class test< T >{
 T Method(object P)
 {
 try {
 return (T)Convert.ChangeType(P, typeof(T));
 } catch(Exception e) {
 return null;
 }
 }
 }
 | 
另一种方法,这一次在组合中有所体现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 
 | 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;
 }
 }
 | 
下一步将尝试实施
| 1
 | public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args ); | 
具有完整的参数类型匹配等
这并不是真正的解决方案,但是在某些情况下,它可能是一个不错的选择:我们可以将一个额外的委托传递给泛型方法。
为了阐明我的意思,我们举个例子。假设我们有一些通用的工厂方法,该方法应创建T的实例,然后希望它调用另一个方法进行通知或其他初始化。
考虑以下简单的类:
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | public class Example{
 // ...
 
 public static void PostInitCallback(Example example)
 {
 // Do something with the object...
 }
 }
 | 
以及以下静态方法:
| 12
 3
 4
 5
 6
 
 | public static T CreateAndInit< T >() where T : new(){
 var t = new T();
 // Some initialization code...
 return t;
 }
 | 
所以现在我们必须做:
| 12
 
 | var example = CreateAndInit<Example>();Example.PostInitCallback(example);
 | 
但是,我们可以更改方法以增加一个委托:
| 12
 3
 4
 5
 6
 7
 8
 
 | 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;
 }
 | 
现在我们可以将调用更改为:
| 1
 | var example = CreateAndInit<Example>(Example.PostInitCallback); | 
显然,这仅在非常特定的情况下有用。但这是最干净的解决方案,从某种意义上说,我们可以保证编译时的安全性,不涉及任何"黑客"行为,并且代码非常简单。
好的,伙计们:感谢所有的鱼。现在有了您的答案和我的研究(尤其是有关将泛型类型限制为基元的文章),我将向您介绍我的解决方案。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 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是否存在该方法。
另一个选择是通过将类型限制为IConvertible(所有基本类型都实现IConvertible)来确保您发送的对象是可转换对象。这将允许您非常灵活地将参数转换为给定类型。
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | Class test< T >{
 int method1(IConvertible Parameter1){
 
 IFormatProvider provider = System.Globalization.CultureInfo.CurrentCulture.GetFormat(typeof(T));
 
 T temp = Parameter1.ToType(typeof(T), provider);
 }
 }
 | 
您也可以像以前一样使用"对象"类型来对此进行更改。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | 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
 }
 }
 }
 | 
您是要执行以下操作吗?
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | 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限制为ValueType:
| 1
 | class test1< T > where T: struct | 
此处的"结构"表示值类型。
字符串是类,而不是值类型。
int,float,Enums都是值类型。
顺便说一句,编译器不接受调用静态方法或访问"类型参数"上的静态成员,如以下示例所示,它们不会编译:(
| 12
 3
 4
 5
 
 | class MyStatic { public static int MyValue=0; }class Test< T > where T: MyStatic
 {
 public void TheTest() { T.MyValue++; }
 }
 | 
=>错误1'T'是'类型参数',在给定的上下文中无效
SL。
您可能需要阅读我以前的文章,即将泛型类型限制为基本类型。这可能会为您提供一些指针,以限制可以传递给泛型的类型(因为TypeParse显然仅可用于一定数量的基元(string.TryParse显然是例外,这没有意义)。
一旦对类型有了更多的了解,就可以尝试解析它。您可能需要在其中添加一些难看的开关(以调用正确的TryParse),但是我认为您可以实现所需的功能。
如果您需要我进一步解释以上任何内容,请询问:)
你可能做不到。
首先,如果可能的话,您需要对T设置更严格的限制,以便类型检查器可以确保对T的所有可能替代实际上都有一个称为TryParse的静态方法。
静态不是这样工作的。您必须将静态变量视为Global类中的一种,即使它们分布在许多类型中。我的建议是使其成为T实例内部的属性,该属性可以访问必要的静态方法。
T也是某物的实际实例,就像其他任何实例一样,您也无法通过实例化的值访问该类型的静态变量。以下是操作示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | 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()
 }
 |