英文:
Type constraint on method for arithmetic types
问题
I've been messing around with generic methods for my own console applications, because some operations just seemed really common to me.
I'm currently wandering if there's a way to constrain a method's input type to a specific set of types in hard code by means of listing/methods that they contain, which could mean that I don't have to suppress warnings in my code if the assumption is there. Here's my current code:
static T GetNumber<T>() where T : new()
{
Type type = typeof(T);
MethodInfo TryParse = (from item in type.GetMethods() where item.Name == "TryParse" select item).ElementAt(0);
while(true)
{
string input = NotNullInput();
object[] parameters = new object[] { input, new T() };
#pragma warning disable CS8605
if (!(bool)TryParse.Invoke(new T(), parameters))
Console.WriteLine($"Invalid {type.Name} input");
else
return (T)parameters[1];
#pragma warning restore CS8605
}
}
Just makes sure the user puts in the correct format, and I know that it would probably only ever be used on types like int, float, double, long etc. I know all the types I've thought of using contained the TryParse method, so if there's a way to assume that, it would fix everything.
Also open to suggestions on how to improve the code because I'm still learning how to mess around with types and reflection.
英文:
I've been messing around with generic methods for my own console applications, because some operations just seemed really common to me.
I'm currently wandering if there's a way to constrain a method's input type to a specific set of types in hard code by means of listing/methods that they contain, which could mean that I don't have to suppress warnings in my code if the assumption is there. Here's my current code:
static T GetNumber<T>() where T : new()
{
Type type = typeof(T);
MethodInfo TryParse = (from item in type.GetMethods() where item.Name == "TryParse" select item).ElementAt(0);
while(true)
{
string input = NotNullInput();
object[] parameters = new object[] { input, new T() };
#pragma warning disable CS8605
if (!(bool)TryParse.Invoke(new T(), parameters))
Console.WriteLine($"Invalid {type.Name} input");
else
return (T)parameters[1];
#pragma warning restore CS8605
}
}
Just makes sure the user puts in the correct format, and I know that it would probably only ever be used on types like int, float, double, long etc. I know all the types I've thought of using contained the TryParse method, so if there's a way to assume that, it would fix everything.
Also open to suggestions on how to improve the code because I'm still learning how to mess around with types and reflection.
答案1
得分: 2
有一个内置接口表达了“这个类型有一个TryParse
方法”的想法,从.NET 7开始 - IParseable<T>
。
您可以将T
约束为该类型,它不仅适用于数字,还适用于实现IParseable<T>
的任何类型。如果您只希望它适用于数字,还有子接口INumber<T>
,您可以使用它来代替。
示例:
public static T ParseInputAsTypeUntilSuccessful<T>() where T: IParsable<T> {
while (true) {
if (T.TryParse(Console.ReadLine(), CultureInfo.InvariantCulture, out var result)) {
return result;
} else {
Console.WriteLine($"无效的 {typeof(T).Name} 输入!");
}
}
}
请注意,您需要指定一个IFormatProvider
或null
,在这里我使用了CultureInfo.InvariantCulture
。
英文:
There is a built-in interface that expresses the idea of "this type has a TryParse
method" since .NET 7 - IParseable<T>
.
You can constrain T
to that type, and it will work not just for numbers, but any type that implements IParseable<T>
. If you only want it to work for numbers, there is also the subinterface INumber<T>
that you can use instead.
Example:
public static T ParseInputAsTypeUntilSuccessful<T>() where T: IParsable<T> {
while (true) {
if (T.TryParse(Console.ReadLine(), CultureInfo.InvariantCulture, out var result)) {
return result;
} else {
Console.WriteLine($"Invalid {typeof(T).Name} input!");
}
}
}
Note that you need to specify an IFormatProvider
or null
, and here I have used CultureInfo.InvariantCulture
.
答案2
得分: 1
调用方可以传递方法本身而不是类型(类型会被推断)。
如果您这样编写方法:
public static T GetNumber<T>(Func<string, T> func)
{
while (true)
{
string input = NotNullInput();
try
{
return func(input);
}
catch
{
Console.WriteLine($"Invalid {typeof(T).Name} input");
}
}
}
然后可以像这样调用它:
var myInteger = GetNumber(int.Parse);
或者
var myDecimal = GetNumber(decimal.Parse);
甚至
byte[] myArray = GetNumber(Convert.FromBase64String);
请注意,传递解析委托会自动为您定义 T
,因此您不必显式传递 T
。
英文:
The caller can pass the method itself instead of the type (the type gets inferred).
If you write the method this way:
public static T GetNumber<T>(Func<string,T> func)
{
while(true)
{
string input = NotNullInput();
try
{
return func(input);
}
catch
{
Console.WriteLine($"Invalid {typeof(T).Name} input");
}
}
}
Then you'd call it like this:
var myInteger = GetNumber(int.Parse);
Or
var myDecimal = GetNumber(decimal.Parse);
Or even
byte[] myArray = GetNumber(Convert.FromBase64String);
Notice that passing the parsing delegate automatically defines T
for you, so you don't have to pass T
explicitly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论