我无法将对象转换为通用IList。我有一组in语句试图解决这个问题,但必须有更好的方法来做到这一点。
这是我目前的方法:
string values;
if (colFilter.Value is IList<int>)
{
values = BuildClause((IList<int>)colFilter.Value, prefix);
}
else if (colFilter.Value is IList<string>)
{
values = BuildClause((IList<string>)colFilter.Value, prefix);
}
else if (colFilter.Value is IList<DateTime>)
{
values = BuildClause((IList<DateTime>)colFilter.Value, prefix);
}
else if (...) //etc.
我想做的是:
values = BuildClause((IList<colFilter.ColumnType>)colFilter.Value, prefix);
或
values = BuildClause((IList<typeof(colFilter.ColumnType)>)colFilter.Value, prefix);
或
values = BuildClause((IList<colFilter.ColumnType.GetType()>)colFilter.Value, prefix);
其中每个都会产生此编译器错误: 找不到类型或命名空间名称'colFilter'(您是否缺少using指令或程序集引用?)
在我的例子中,colFilter.ColumnType是int,string,datetime等。我不知道为什么这不起作用。
有什么想法吗?
编辑:这是C#2.0
编辑#2
这是BuildClause方法(我对每种类型都有重载):
private static string BuildClause(IList<int> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, false);
}
private static string BuildClause(IList<String> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, true);
}
private static string BuildClause(IList<DateTime> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, true);
}
//.. etc for all types
private static string BuildClause<T>(IList<T> inClause, string strPrefix, bool addSingleQuotes)
{
StringBuilder sb = new StringBuilder();
//Check to make sure inclause has objects
if (inClause.Count > 0)
{
sb.Append(strPrefix);
sb.Append(" IN(");
for (int i = 0; i < inClause.Count; i++)
{
if (addSingleQuotes)
{
sb.AppendFormat("'{0}'", inClause[i].ToString().Replace("'", "''"));
}
else
{
sb.Append(inClause[i].ToString());
}
if (i != inClause.Count - 1)
{
sb.Append(",");
}
}
sb.Append(") ");
}
else
{
throw new Exception("Item count for In() Clause must be greater than 0.");
}
return sb.ToString();
}
答案 0 :(得分:5)
没有办法将方法重载和泛型联系起来:尽管它们看起来很相似,但它们却截然不同。具体来说,重载允许您根据使用的参数类型执行不同的事情;而泛型允许你做完全相同的事情,无论使用何种类型。
如果你的BuildClause方法被重载并且每个重载都做了不同的事情(不仅仅是使用的类型不同,但是逻辑真的不同,在这种情况下 - 选择是否添加引号)然后在某处,最终,你是不得不说“如果类型是这样做,如果类型是这样做”(我称之为“开启类型”)。
另一种方法是避免使用“开启类型”逻辑并将其替换为多态。假设您有StringColFilter : ColFilter<string>
和IntColFilter : ColFilter<int>
,那么每个都可以覆盖ColFilter<T>
中的虚拟方法并提供自己的BuildClause实现(或者只是一些有助于BuildClause进程的数据)它)。但是,您需要显式创建正确的ColFilter子类型,它只是将“开关类型”逻辑移动到应用程序中的另一个位置。如果您很幸运,它会将该逻辑移动到您应用程序中您知道要处理的类型的位置,然后您可以在应用程序的不同位置明确创建不同的ColFilter并一般地处理它们以后。
考虑这样的事情:
abstract class ColFilter<T>
{
abstract bool AddSingleQuotes { get; }
List<T> Values { get; }
}
class IntColFilter<T>
{
override bool AddSingleQuotes { get { return false; } }
}
class StringColFilter<T>
{
override bool AddSingleQuotes { get { return true; } }
}
class SomeOtherClass
{
public static string BuildClause<T>(string prefix, ColFilter<T> filter)
{
return BuildClause(prefix, filter.Values, filter.AddSingleQuotes);
}
public static string BuildClause<T>(string prefix, IList<T> values, bool addSingleQuotes)
{
// use your existing implementation, since here we don't care about types anymore --
// all we do is call ToString() on them.
// in fact, we don't need this method to be generic at all!
}
}
当然,这也可以解决ColFilter是否应该知道引号的问题,但这是一个设计问题,值得另一个问题:)
我也支持其他海报说,如果你试图通过将字符串连接在一起来构建创建SQL语句的东西,你应该停止这样做并转移到更容易的参数化查询,更重要的是,更安全。
答案 1 :(得分:2)
BuildClause()函数是什么样的。
在我看来,您可以在IList上创建BuildClause()作为扩展方法,并且可以将值附加在一起。我假设您只想在不同类型上调用.ToString()方法。
答案 2 :(得分:2)
如果在C#3.0中正确使用泛型,则可以通过隐式类型实现所需(int C#2.0,您可能需要指定类型)。如果您的BuildClause方法是通用的,它应该自动采用传递给其通用参数的任何类型:
public IList<T> BuildClause<T>(IList<T> value, object prefix)
{
Type type = typeof(T);
if (type == typeof(string))
{
// handle string
}
else if (type == typeof(int))
{
// handle int
}
// ...
}
public class ColumnFilter<T>:
where T: struct
{
public IList<T> Value { get; set; }
}
var colFilter = new ColumnFilter<string>
{
Value = new { "string 1", "string 2", "string 3" }
}
IList<string> values = BuildClause(colFilter.Value, prefix);
使用泛型,您可以删除ColumnFilter的ColumnType属性。由于它是通用的,与您的BuildClause方法一起,您可以通过执行typeof(T)轻松确定类型。
答案 3 :(得分:2)
我无法将对象转换为通用
Casting是一个运行时操作。
Generic是编译时信息。
不要越过溪流。
另外 - 如果你使用了一个不错的sql参数化生成器 - 它会为你添加单引号。
答案 4 :(得分:1)
我不明白这个问题。这个对我有用。它可以像放弃演员一样简单吗?我错过了什么?
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1 {
class Foo<T> : List<T> {
}
class Program {
static void Main(string[] args) {
var a = new Foo<int>();
a.Add(1);
var b = new Foo<string>();
b.Add("foo");
Console.WriteLine(BuildClause(a, "foo", true));
Console.WriteLine(BuildClause(b, "foo", true));
}
private static string BuildClause<T>(IList<T> inClause, string strPrefix, bool addSingleQuotes) {
StringBuilder sb = new StringBuilder();
//Check to make sure inclause has objects
if (inClause.Count == 0)
throw new Exception("Item count for In() Clause must be greater than 0.");
sb.Append(strPrefix).Append(" IN(");
foreach (var Clause in inClause) {
if (addSingleQuotes)
sb.AppendFormat("'{0}'", Clause.ToString().Replace("'", "''"));
else
sb.Append(Clause.ToString());
sb.Append(',');
}
sb.Length--;
sb.Append(") ");
return sb.ToString();
}
}
}
答案 5 :(得分:0)
必须在编译时知道IList的类型。根据您想要做的事情,您可以将列表转换为IList或IEnumerable(无泛型),然后迭代对象