1

私は自分自身を隅にコーディングしました、そしてあなたの助けが私を再び掘り出すことを望みます。正しい方向に。

そこで、ソリューションを汎用的にしたいマイナーなSQLiteラッパーを実装しました(全員ではありません)。その後、これらのクラスとインターフェースの使用法はあまり直感的でも一般的でもないことに気づきました。

下から始めて上に向かっていきましょう。DataRowテーブル行の基本クラスとして機能するというクラスを作成しました。クラスDataRow自体にはプロパティしかありませんId(すべての行にプロパティが必要なため)。これにより、次の定義が得られます。class DataRow { public int Id { get; set; } }

このDataRowクラスを使用して、各テーブルです。また、データベーステーブル用に、1つのジェネリックインターフェイスと1つのジェネリック基本クラスを作成しました。定義は次のようになります。

internal interface ITable<T>
    where T : DataRow, new()
{
    T Select(int id);
    List<T> Select(List<int> ids);
    int Insert(T t);
    void Update(T t);
    bool Delete(int id);
}

public class Table<T> : ITable<T>
    where T : DataRow, new()
{
    // Commented out to protect you from a minor case of serious brain damage.
}

この設定により、簡潔な定義を作成できます。実際、彼らは本当に叙事詩的である傾向があります。言うことを誇りに思います。

public class Car : DataRow
{
    public decimal ParkingTicketDebt { get; set; }
    public DateTime WhenWifeWillAllowReplacement { get; set; }
    public bool CanTransformIntoSomethingAwesome { get; set; }
}

public class Cars : Table<Car> {
    // Yep, that's all. You can go home now, folks. There's nothing here. Nothing at all. Especially not a great treasure of gold. Whops... I mean... there's really not. Not that I'm aware of, anyway... I mean, there could be. Not that I wouldn't say if I had any information on this great trasure of gold that might exist. But I know nothing of such an item. I really don't, so you can stop thinking about this great treasure of gold. Since I don't know anything about it, the chance that it even exist is extremely low. Miniscule. I mean, you would probably not find anything, not even if you digged for, like, a really long time. Seven years or something. Oookay. Slowly fading away...
}

お気づきかもしれませんがCars、データベース内のテーブルの名前を決定するために、のクラスタイプ名を使用しています。同様に、私はリフレクションを実行しCar、そのパブリックプロパティの名前とタイプを使用して、データベースの値を取得/設定します。そして、はい、私はEntityFrameworkの簡略版をコーディングしている最中であることを認識しています。これは本当に愚かでかなり時間がかかるように聞こえます。

とにかく、これがクラスの使用例Carsです。私が誇りに思っていることを思い出してください。

new Cars().Delete(3497); // Note that I have a great number of (expensive) cars.

いいですね 1つのわずかな問題。これは、データベースに存在するテーブルの数に固有の、強く型付けされたコードを作成する必要があることを意味します。そして、私は特定のコードが好きではありません。私は一般的なコードが好きです。

あなたはここで私がそれをやり過ぎていると主張し始めるかもしれません。それでは、これをお話ししましょう。あなたは正解です私はやり過ぎです!戦車にひかれた死んだ男をわざと火炎放射させています。7回。

それで私は少し実験を始めて、この繊細な解決策を思いつきました:

[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[WebMethod(EnableSession = true)]
public int CreateEmptyRow(string tableName)
{
    var tableType = Type.GetType(tableName);
    if (tableType == null)
        throw new TypeLoadException("Dumbass. That table doesn't exist");

    var instance = Activator.CreateInstance(tableType) as ITable<dynamic>;
    if (instance == null)
        throw new TypeLoadException("Idiot. That type isn't a table");

    return instance.Insert(new DataRow());
}

なぜ誰かが空の行を作成したいかわからない場合、私は本当に理解できることに注意してください。

では、これの何が問題になっていますか?まあ、それはコンパイルされません。エラーは次のとおりThere is no implicit reference conversion from 'dynamic' to 'DataRow'です。Googleで検索しても、結果はほとんどありませんでした。

問題は明らかにActivator.CreateInstance(tableType) as ITable<dynamic>です。私はActivator.CreateInstance(tableType) as ITable<Table<DataRow>>、このエラーを私に与えた試みのようなものを試しました:The type 'DataRow' must be convertible to 'DataRow'

4

2 に答える 2

2

したがって、コメントに書かれているように、Imは追加の非ジェネリックインターフェイスを追加します。

 interface ITable
{
    DataRow Select(int id);
    IEnumerable<DataRow> Select(List<int> ids);
    int Insert(DataRow t);
    void Update(DataRow t);

}
interface ITable<T>  where T : DataRow, new()
{
    T Select(int id);
    List<T> Select(List<int> ids);
    int Insert(T t);
    void Update(T t);
    bool Delete(int id);
}

class Table<T> : ITable<T>, ITable where T : DataRow, new()
{

    public T Select(int id)
    {
        return new T();
    }

    public List<T> Select(List<int> ids)
    {
        return new List<T>();
    }

    public int Insert(T t)
    {
        return 1;
    }

    public void Update(T t)
    {
    }

    public bool Delete(int id)
    {
        return true;
    }

    DataRow ITable.Select(int id)
    {
        return this.Select(id);
    }

    IEnumerable<DataRow> ITable.Select(List<int> ids)
    {
        return this.Select(ids);
    }

    public int Insert(DataRow t)
    {
        return this.Insert(t);
    }

    public void Update(DataRow t)
    {
        this.Update(t);
    }
}

CreateEmptyRowこれは、 \Selectメソッドを実装する方法です。

      public static int CreateEmptyRow(string tableName)
    {
        var tableType = Type.GetType(tableName);
        if (tableType == null)
            throw new TypeLoadException("Dumbass. That table doesn't exist");

        var instance = Activator.CreateInstance(tableType) as ITable;
        if (instance == null)
            throw new TypeLoadException("Idiot. That type isn't a table");

        return instance.Insert(new DataRow());
    }
    public static List<DataRow> Select(List<int> ids, string tableName)
    {
        var tableType = Type.GetType(tableName);
        if (tableType == null)
            throw new TypeLoadException("Dumbass. That table doesn't exist");

        var instance = Activator.CreateInstance(tableType) as ITable;
        if (instance == null)
            throw new TypeLoadException("Idiot. That type isn't a table");

        return instance.Select(ids).ToList();
    }

このような一般的なソリューションが必要な場合、selectメソッド(たとえば)はIEnumerable\ Listofのみを返すことができます。これは、提供されている拡張メソッドDataRowを使用して解決できます。Cast

var myList = Select(null, "Cars").Cast<Car>();

注:ご存知かもしれませんが、Carsクラスを名前でインスタンス化するには、ここでスキップした名前空間も指定する必要があります。おそらく、Table<T>クラスも抽象である必要があります。

于 2013-03-03T14:20:43.160 に答える
1

DataRow1 つの問題は、 のサブクラスを受け取るテーブルにを挿入しようとしているDataRowため、コンパイルできたとしても、実行時に例外が発生することです。

挿入する一般的な行の型を見つけて、その型の新しいインスタンスを挿入する必要があります。

object instance = Activator.CreateInstance(tableType);
var tableInterface = tableType.GetInterfaces().FirstOrDefault(it => it.IsGenericType && it.GetGenericTypeDefinition() == typeof(ITable<>));
if(tableInterface == null) throw new ArgumentException("Type is not a table type");

var rowType = tableInterface.GetGenericArguments()[0];
var newRow = Activator.CreateInstance(rowType);

MethodInfo insertMethod = tableInterface.GetMethod("Insert");
return (int)insertMethod.Invoke(instance, new object[] { newRow });

ただしCreateEmptyRow、テーブルと行のタイプでメソッドをジェネリックにして、リフレクションを完全に回避できるようです。

public int CreateEmptyRow<TTable, TRow>() 
    where TRow : DataRow, new()
    where TTable : ITable<TRow>, new()
{
    var table = new TTable();
    return table.Insert(new TRow());
}
于 2013-03-03T13:35:50.107 に答える