我有一个简单的方法,我将属性传递为arg
。然后我尝试确定返回字符串,int或decimal的格式。这是方法。
protected T GetValue<T>(T arg, List<string> item, int index)
{
if ((object)arg == null)
return (T)(object)Convert.ToInt32(item[index]);//throws specified cast not valid
if (arg.GetType() == typeof(int))
return (T)(object)Convert.ToInt32(item[index]);
if (arg.GetType() == typeof(string))
return (T)(object)arg.ToString();
if (arg.GetType() == typeof(decimal))
return (T)(object)Convert.ToDecimal(item[index]);
return default(T);
}
问题在于,当我将arg
作为System.String或System.Nullable传入时,它们都是空的。因此,当我对字符串执行specified cast invalid
而对可空的int执行Convert.ToInt32(item[index])
时,我得到arg.ToString()
答案 0 :(得分:3)
当只有少数不相关的类型可能没有共同点时,不要使用泛型。 string
,int
和decimal
是完全不同的类型,除了调用他们的ToString
- 方法和从{object
继承的其他一些方法之外,没有什么可以做的。 1}})。
而是使用三种不同的方法:
protected decimal GetDecimal(decimal arg) { ...}
protected string GetString(string arg) { ...}
protected int GetInt(int arg) { ...}
这样你甚至可以省略arg
- 参数,它似乎只作为正确类型的虚拟实例存在,以便进行通用工作。因此,无论如何你必须在编译时知道正确的类型,所以你也可以通过选择正确的方法直接提供它。
如果你真的 使用泛型,请使用is
- 运算符:
protected T GetValue<T>(T arg, List<string> item, int index)
{
if (arg is int)
return (T)(object)Convert.ToInt32(item[index]);
if (arg is string)
return (T)(object)arg.ToString();
if (arg is decimal)
return (T)(object)Convert.ToDecimal(item[index]);
return default(T);
}
然而,这不是用于制作泛型的。
答案 1 :(得分:3)
你的方法根本不应该是通用的。这就是重载:
protected object GetValue(
object arg, List<string> item, int index)
{
if (arg == null)
//...
else
//whatever seems fit for an object that isn't resolved to
//another overload
}
protected string GetValue(
string arg, List<string> item, int index)
{
return arg; //hmmm, how useful is this?
}
protected decimal GetValue(
decimal arg, List<string> item, int index)
{
return Convert.ToDecimal(item[index]);
}
protected int GetValue(
int arg, List<string> item, int index)
{
return Convert.ToInt32(item[index]);
}
效果更好。当有效类型是有限集时,不要使用泛型。泛型应该适用于符合某些constaints的任何类型T
。
通常,如果您在通用方法中开始需要运行时类型检查,那么您做错了什么!
更新:遵循Servy的评论,如果您需要支持可空的整数,小数等,那么只需编写相应的重载。不过我想在以下情况中指出:
int? i = null;
var result = GetValue((object)i);
如果参数GetValue
实际上是arg
,可以为空的值类型或对象,则无法识别string
内部。除了知道参数是静态类型null
之外,object
没有您可以利用的类型信息。
这显然是非常不同的:
protected int? GetValue(int? arg, List<string> item, int index) { ... }
int? i = null;
var result = GetValue(i);
此处arg
也是null
,但已解决的重载为GetValue(int? arg)
,因此您知道 arg
是可空的int
}。
答案 2 :(得分:0)
可悲的是,我无法理解您发布的代码,但我尽力为您提供有效的解决方案。
在本质上,为什么不在列表中装入对象,然后使用类型参数调用方法,而不是滥用这样的泛型。 这样的事情可以解决问题:
protected T GetValue<T>(List<object> item, int index) {
if (index > item.Count || item[index] is default)
throw new ArgumentException("Very detailed message");
else if (item[index] is T val)
return val;
else
return (T)item[index]; // Will stil throw an exception if cast fails
// Of course you can add different/more checks
}