2009-06-12 15 views
3

オブジェクトを汎用IListにキャストする際に問題があります。私はこれを回避しようとする声明のグループを持っていますが、これを行うにはより良い方法が必要です。C#Generics and Casting Issue

これが私の現在の方法である:

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); 

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. 

は私がやりたいことはこれです

これらのそれぞれ、このコンパイラエラー生成: 型または名前空間名は「colFilter」が見つかりませんでした(?あなたがusingディレクティブまたはアセンブリ参照が不足している)

私の例では、colFilter.ColumnTypeは、intです文字列、日時計などがあります。なぜこれが機能しないのか分かりません。

アイデア?

EDIT:これはここではC#2.0

EDIT#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(); 
    } 

答えて

5

メソッドオーバーロードとジェネリックスを関連付ける方法はありません。類似していますが、それらは非常に異なります。具体的には、オーバーロードを使用すると、使用される引数のタイプに基づいて異なるものをすることができます。ジェネリックスでは使用するタイプにかかわらずと全く同じものを実行できます。

BuildClauseメソッドがオーバーロードされていて、すべてのオーバーロードが異なるもの(使用されているタイプによって異なるだけでなく、実際には異なるロジック、この場合は引用符を追加するかどうかを選択する) 「もしタイプがこれならこれを行う、タイプがそれを行うならば」というようなことを言わなければならない(私はそれを「スイッチオンタイプ」と呼ぶ)。

もう1つの方法は、「スイッチオンタイプ」ロジックを避け、多態性で置き換えることです。 StringColFilter : ColFilter<string>IntColFilter : ColFilter<int>があったとすると、それぞれがColFilter<T>から仮想メソッドをオーバーライドし、独自のBuildClause実装(またはそれを処理するのに役立つ一部のデータ)を提供することができます。しかし、ColFilterの正しいサブタイプを明示的に作成する必要があります。これは、「switch-on-type」ロジックをアプリケーションの別の場所に移動するだけです。あなたが運が良ければ、それはあなたが扱っているタイプの知識を持っているあなたのアプリケーション内の場所にそのロジックを移動します。そして、アプリケーションの異なる場所で異なる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文を作成するものを作成しようとしているなら、おそらくそれをやめて、より安全で簡単なパラメータ化されたクエリに移行してください。

2

関数BuildClause()は次のようになります。

IListでの拡張子メソッドとしてBuildClause()を作成し、その値を追加できます。異なるタイプの.ToString()メソッドを呼び出すだけだと仮定します。

+0

コードを実行します。 私は値= BuildClause(colFilter.Value、prefix)を行った。それはOKと思われる。 colFilter.ValueがタイプIList であることが確かであればOKです。 –

+0

私にとってはうまくいかないようですが、コンパイラエラーが発生します:BuildClauseのオーバーロードは何ですか? – Jon

0

IListの型はコンパイル時にわかっている必要があります。目的に応じて、リストをIListまたはIEnumerable(ジェネリックスなし)にキャストしてからオブジェクトを反復処理することができます。

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)を実行することで簡単に型を判別することができます。

2

I am having trouble casting an object to a generic

キャスティングは実行時操作です。

一般的な情報はコンパイル時の情報です。

ストリームを通過しないでください。

また、適切なSQLパラメータ生成プログラムを使用した場合、単一引用符が追加されます。

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(); 
    } 

    } 

}