My question concerns c# and how to access Static memebers ... Well I don't really know how to explain it (wich kind of is bad for a question isn't it?) I will just give you some sample code:
我的问题涉及到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()
}
}
So thank you guys for your answers (By the way the question is: how would I solve this problem without getting an error). This probably quite an easy question for you!
谢谢你们的回答(顺便问一下:如何在不收到错误的情况下解决这个问题)。这对您来说可能是一个非常简单的问题!
Thanks, Niklas
Edit: Thank you all for your answers!
编辑:谢谢大家的回答!
Though I think the try - catch phrase is the most elegant, I know from my experience with vb that it can really be a bummer. I used it once and it took about 30 minutes to run a program, which later on only took 2 minutes to compute just because I avoided try - catch.
虽然我认为try-catch短语是最优雅的,但我从vb的经验中知道它真的可能是一个无赖。我用过一次,运行一个程序花了大约30分钟,之后只花了2分钟计算,因为我避免了尝试 - 捕获。
This is why I chose the swich statement as the best answer. It makes the code more complicated but on the other hand I imagine it to be relatively fast and relatively easy to read. (Though I still think there should be a more elegant way ... maybe in the next language I learn :P )
这就是我选择swich语句作为最佳答案的原因。它使代码更复杂,但另一方面,我认为它相对快速且相对容易阅读。 (虽然我仍然认为应该有一种更优雅的方式...也许用我学习的下一种语言:P)
Though if you have some other suggestion I am still waiting (and willing to participate)
虽然如果你有其他建议,我还在等待(并愿意参加)
12 个解决方案
#1
2
One more way to do it, this time some reflection in the mix:
还有一种方法,这次是混合中的一些反映:
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;
}
}
The next step would be trying to implement
下一步将是尝试实施
public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args );
With full parameter type matching etc.
具有完整的参数类型匹配等
#2
5
The problem is that TryParse isn't defined on an interface or base class anywhere, so you can't make an assumption that the type passed into your class will have that function. Unless you can contrain T in some way, you'll run into this a lot.
问题是TryParse没有在任何地方的接口或基类上定义,所以你不能假设传入你的类的类型将具有该功能。除非你能以某种方式反对T,否则你会遇到很多。
Constraints on Type Parameters
类型参数的约束
#3
3
Short answer, you can't.
简短的回答,你不能。
Long answer, you can cheat:
答案很长,你可以作弊:
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();
}
}
I made a static dictionary holding a delegate for the TryParse method of every type I might want to use. I then wrote a generic method to look up the dictionary and pass on the call to the appropriate delegate. Since every delegate has a different type, I just store them as object references and cast them back to the appropriate generic type when I retrieve them. Note that for the sake of a simple example I have omitted error checking, such as to check whether we have an entry in the dictionary for the given type.
我创建了一个静态字典,其中包含我可能想要使用的每种类型的TryParse方法的委托。然后我编写了一个通用方法来查找字典并将调用传递给相应的委托。由于每个委托都有不同的类型,我只是将它们存储为对象引用,并在检索它们时将它们转换回适当的泛型类型。请注意,为了一个简单的例子,我省略了错误检查,例如检查我们是否在给定类型的字典中有一个条目。
#4
3
To access a member of a specific class or interface you need to use the Where keyword and specify the interface or base class that has the method.
要访问特定类或接口的成员,您需要使用Where关键字并指定具有该方法的接口或基类。
In the above instance TryParse does not come from an interface or base class, so what you are trying to do above is not possible. Best just use Convert.ChangeType and a try/catch statement.
在上面的实例中,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;
}
}
}
#5
2
Ok guys: Thanks for all the fish. Now with your answers and my research (especially the article on limiting generic types to primitives) I will present you my solution.
好的家伙:感谢所有的鱼。现在有了你的答案和我的研究(特别是关于将泛型类型限制为原语的文章),我将向您介绍我的解决方案。
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
Do you mean to do something like this:
你的意思是做这样的事情:
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
}
}
}
Unfortunately you can't check for the TryParse pattern as it is static - which unfortunately means that it isn't particularly well suited to generics.
不幸的是,你无法检查TryParse模式,因为它是静态的 - 不幸的是,它不是特别适合于泛型。
#7
1
The only way to do exactly what you're looking for would be to use reflection to check if the method exists for T.
要完成你正在寻找的东西的唯一方法是使用反射来检查T的方法是否存在。
Another option is to ensure that the object you send in is a convertible object by restraining the type to IConvertible (all primitive types implement IConvertible). This would allow you to convert your parameter to the given type very flexibly.
另一种选择是通过将类型限制为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);
}
}
You could also do a variation on this by using an 'object' type instead like you had originally.
你也可以通过使用'对象'类型来改变它,就像你原来的那样。
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
This isn't really a solution, but in certain scenarios it could be a good alternative: We can pass an additional delegate to the generic method.
这不是一个真正的解决方案,但在某些情况下它可能是一个很好的选择:我们可以将另一个委托传递给泛型方法。
To clarify what I mean, let's use an example. Let's say we have some generic factory method, that should create an instance of T, and we want it to then call another method, for notification or additional initialization.
为了澄清我的意思,让我们举个例子。假设我们有一些通用工厂方法,它应该创建一个T实例,然后我们希望它再调用另一个方法,用于通知或其他初始化。
Consider the following simple class:
考虑以下简单类:
public class Example
{
// ...
public static void PostInitCallback(Example example)
{
// Do something with the object...
}
}
And the following static method:
以下静态方法:
public static T CreateAndInit<T>() where T : new()
{
var t = new T();
// Some initialization code...
return t;
}
So right now we would have to do:
所以现在我们必须这样做:
var example = CreateAndInit<Example>();
Example.PostInitCallback(example);
However, we could change our method to take an additional delegate:
但是,我们可以更改我们的方法以获取额外的委托:
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;
}
And now we can change the call to:
现在我们可以将呼叫改为:
var example = CreateAndInit<Example>(Example.PostInitCallback);
Obviously this is only useful in very specific scenarios. But this is the cleanest solution in the sense that we get compile time safety, there is no "hacking" involved, and the code is dead simple.
显然,这仅适用于非常具体的场景。但这是最干净的解决方案,因为我们得到了编译时的安全性,没有涉及“黑客”,而且代码很简单。
#9
0
You probably cant do it.
你可能不能这样做。
First of all if it should be possible you would need a tighter bound on T so the typechecker could be sure that all possible substitutions for T actually had a static method called TryParse.
首先,如果有可能你需要更严格的T绑定,那么类型检查器可以确定T的所有可能替换实际上都有一个名为TryParse的静态方法。
#10
0
You may want to read my previous post on limiting generic types to primitives. This may give you some pointers in limiting the type that can be passed to the generic (since TypeParse is obviously only available to a set number of primitives ( string.TryParse obviously being the exception, which doesn't make sense).
您可能想阅读我之前关于将泛型类型限制为基元的帖子。这可能会为您提供一些限制可以传递给泛型的类型的指针(因为TypeParse显然只能用于一定数量的基元(string.TryParse显然是例外,这没有意义)。
Once you have more of a handle on the type, you can then work on trying to parse it. You may need a bit of an ugly switch in there (to call the correct TryParse ) but I think you can achieve the desired functionality.
一旦你有了更多关于类型的句柄,你就可以尝试解析它。你可能需要一些丑陋的开关(调用正确的TryParse),但我认为你可以实现所需的功能。
If you need me to explain any of the above further, then please ask :)
如果您需要我进一步解释上述任何内容,请询问:)
#11
0
Best code: restrict T to ValueType this way:
最佳代码:以这种方式将T限制为ValueType:
class test1<T> where T: struct
A "struct" here means a value type. String is a class, not a value type. int, float, Enums are all value types.
这里的“struct”表示值类型。 String是一个类,而不是值类型。 int,float,Enums都是值类型。
btw the compiler does not accept to call static methods or access static members on 'type parameters' like in the following example which will not compile :(
顺便说一句,编译器不接受调用静态方法或访问“类型参数”上的静态成员,如下例中不会编译:(
class MyStatic { public static int MyValue=0; }
class Test<T> where T: MyStatic
{
public void TheTest() { T.MyValue++; }
}
=> Error 1 'T' is a 'type parameter', which is not valid in the given context
=>错误1'T'是'类型参数',在给定的上下文中无效
SL.
#12
-1
That is not how statics work. You have to think of statics as sort of in a Global class even if they are are spread across a whole bunch of types. My recommendation is to make it a property inside the T instance that can access the necessary static method.
这不是静力学的工作方式。你必须将静态视为全局类中的一种,即使它们分布在一大堆类型中。我的建议是使它成为T实例中可以访问必要的静态方法的属性。
Also T is an actual instance of something, and just like any other instance you are not able to access the statics for that type, through the instantiated value. Here is an example of what to do:
此外,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
One more way to do it, this time some reflection in the mix:
还有一种方法,这次是混合中的一些反映:
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;
}
}
The next step would be trying to implement
下一步将是尝试实施
public static TRet CallStaticMethod<TRet>( object obj, string methodName, params object[] args );
With full parameter type matching etc.
具有完整的参数类型匹配等
#2
5
The problem is that TryParse isn't defined on an interface or base class anywhere, so you can't make an assumption that the type passed into your class will have that function. Unless you can contrain T in some way, you'll run into this a lot.
问题是TryParse没有在任何地方的接口或基类上定义,所以你不能假设传入你的类的类型将具有该功能。除非你能以某种方式反对T,否则你会遇到很多。
Constraints on Type Parameters
类型参数的约束
#3
3
Short answer, you can't.
简短的回答,你不能。
Long answer, you can cheat:
答案很长,你可以作弊:
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();
}
}
I made a static dictionary holding a delegate for the TryParse method of every type I might want to use. I then wrote a generic method to look up the dictionary and pass on the call to the appropriate delegate. Since every delegate has a different type, I just store them as object references and cast them back to the appropriate generic type when I retrieve them. Note that for the sake of a simple example I have omitted error checking, such as to check whether we have an entry in the dictionary for the given type.
我创建了一个静态字典,其中包含我可能想要使用的每种类型的TryParse方法的委托。然后我编写了一个通用方法来查找字典并将调用传递给相应的委托。由于每个委托都有不同的类型,我只是将它们存储为对象引用,并在检索它们时将它们转换回适当的泛型类型。请注意,为了一个简单的例子,我省略了错误检查,例如检查我们是否在给定类型的字典中有一个条目。
#4
3
To access a member of a specific class or interface you need to use the Where keyword and specify the interface or base class that has the method.
要访问特定类或接口的成员,您需要使用Where关键字并指定具有该方法的接口或基类。
In the above instance TryParse does not come from an interface or base class, so what you are trying to do above is not possible. Best just use Convert.ChangeType and a try/catch statement.
在上面的实例中,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;
}
}
}
#5
2
Ok guys: Thanks for all the fish. Now with your answers and my research (especially the article on limiting generic types to primitives) I will present you my solution.
好的家伙:感谢所有的鱼。现在有了你的答案和我的研究(特别是关于将泛型类型限制为原语的文章),我将向您介绍我的解决方案。
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
Do you mean to do something like this:
你的意思是做这样的事情:
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
}
}
}
Unfortunately you can't check for the TryParse pattern as it is static - which unfortunately means that it isn't particularly well suited to generics.
不幸的是,你无法检查TryParse模式,因为它是静态的 - 不幸的是,它不是特别适合于泛型。
#7
1
The only way to do exactly what you're looking for would be to use reflection to check if the method exists for T.
要完成你正在寻找的东西的唯一方法是使用反射来检查T的方法是否存在。
Another option is to ensure that the object you send in is a convertible object by restraining the type to IConvertible (all primitive types implement IConvertible). This would allow you to convert your parameter to the given type very flexibly.
另一种选择是通过将类型限制为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);
}
}
You could also do a variation on this by using an 'object' type instead like you had originally.
你也可以通过使用'对象'类型来改变它,就像你原来的那样。
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
This isn't really a solution, but in certain scenarios it could be a good alternative: We can pass an additional delegate to the generic method.
这不是一个真正的解决方案,但在某些情况下它可能是一个很好的选择:我们可以将另一个委托传递给泛型方法。
To clarify what I mean, let's use an example. Let's say we have some generic factory method, that should create an instance of T, and we want it to then call another method, for notification or additional initialization.
为了澄清我的意思,让我们举个例子。假设我们有一些通用工厂方法,它应该创建一个T实例,然后我们希望它再调用另一个方法,用于通知或其他初始化。
Consider the following simple class:
考虑以下简单类:
public class Example
{
// ...
public static void PostInitCallback(Example example)
{
// Do something with the object...
}
}
And the following static method:
以下静态方法:
public static T CreateAndInit<T>() where T : new()
{
var t = new T();
// Some initialization code...
return t;
}
So right now we would have to do:
所以现在我们必须这样做:
var example = CreateAndInit<Example>();
Example.PostInitCallback(example);
However, we could change our method to take an additional delegate:
但是,我们可以更改我们的方法以获取额外的委托:
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;
}
And now we can change the call to:
现在我们可以将呼叫改为:
var example = CreateAndInit<Example>(Example.PostInitCallback);
Obviously this is only useful in very specific scenarios. But this is the cleanest solution in the sense that we get compile time safety, there is no "hacking" involved, and the code is dead simple.
显然,这仅适用于非常具体的场景。但这是最干净的解决方案,因为我们得到了编译时的安全性,没有涉及“黑客”,而且代码很简单。
#9
0
You probably cant do it.
你可能不能这样做。
First of all if it should be possible you would need a tighter bound on T so the typechecker could be sure that all possible substitutions for T actually had a static method called TryParse.
首先,如果有可能你需要更严格的T绑定,那么类型检查器可以确定T的所有可能替换实际上都有一个名为TryParse的静态方法。
#10
0
You may want to read my previous post on limiting generic types to primitives. This may give you some pointers in limiting the type that can be passed to the generic (since TypeParse is obviously only available to a set number of primitives ( string.TryParse obviously being the exception, which doesn't make sense).
您可能想阅读我之前关于将泛型类型限制为基元的帖子。这可能会为您提供一些限制可以传递给泛型的类型的指针(因为TypeParse显然只能用于一定数量的基元(string.TryParse显然是例外,这没有意义)。
Once you have more of a handle on the type, you can then work on trying to parse it. You may need a bit of an ugly switch in there (to call the correct TryParse ) but I think you can achieve the desired functionality.
一旦你有了更多关于类型的句柄,你就可以尝试解析它。你可能需要一些丑陋的开关(调用正确的TryParse),但我认为你可以实现所需的功能。
If you need me to explain any of the above further, then please ask :)
如果您需要我进一步解释上述任何内容,请询问:)
#11
0
Best code: restrict T to ValueType this way:
最佳代码:以这种方式将T限制为ValueType:
class test1<T> where T: struct
A "struct" here means a value type. String is a class, not a value type. int, float, Enums are all value types.
这里的“struct”表示值类型。 String是一个类,而不是值类型。 int,float,Enums都是值类型。
btw the compiler does not accept to call static methods or access static members on 'type parameters' like in the following example which will not compile :(
顺便说一句,编译器不接受调用静态方法或访问“类型参数”上的静态成员,如下例中不会编译:(
class MyStatic { public static int MyValue=0; }
class Test<T> where T: MyStatic
{
public void TheTest() { T.MyValue++; }
}
=> Error 1 'T' is a 'type parameter', which is not valid in the given context
=>错误1'T'是'类型参数',在给定的上下文中无效
SL.
#12
-1
That is not how statics work. You have to think of statics as sort of in a Global class even if they are are spread across a whole bunch of types. My recommendation is to make it a property inside the T instance that can access the necessary static method.
这不是静力学的工作方式。你必须将静态视为全局类中的一种,即使它们分布在一大堆类型中。我的建议是使它成为T实例中可以访问必要的静态方法的属性。
Also T is an actual instance of something, and just like any other instance you are not able to access the statics for that type, through the instantiated value. Here is an example of what to do:
此外,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()
}