Frage

Ich habe versucht, eine einfache Basisklasse zu erstellen, die einige meiner Konventionen für den Datenbankzugriff zusammenfasst. Ich erstelle im Allgemeinen ein Sproc mit dem Namen "Products_Retrieve_Product", um ein Produkt basierend auf ProductID auszuwählen. Ich möchte, dass die Methode in der Basisklasse "abgerufen" wird, um den Typ zurückzugeben, den die abgeleitete Klasse in ihrer Definition liefert. Ist das, was ich versuche, mit Generika möglich zu sein?

public class MyBaseClass <T>
{
    private string _className;

    public MyBaseClass ()
    {
        _className = this.GetType().Name;
    }

    public virtual T Retrieve(int ID)
    {
        Database db = DatabaseFactory.CreateDatabase();
        DbCommand dbCommand = db.GetStoredProcCommand(String.Format("{0}s_Retrieve_{0}", _className));
        db.AddInParameter(dbCommand, String.Format("@{0}ID", _className), DbType.Int32, ID);

        using (IDataReader dr = db.ExecuteReader(dbCommand))
        {
            if (dr.Read())
            {
                BOLoader.LoadDataToProps(this, dr);
            }
        }
        return (T)this;
    }
}
War es hilfreich?

Lösung

Ich denke, dass du so etwas tun willst:

class MyBaseClass<T> where T : MyBaseClass<T>, new()
{
    public T Retrieve()
    {
        return new T();
    }
}

class Foo : MyBaseClass<Foo>
{
}

class Program
{
    public static void Main()
    {
        Foo f = new Foo();
        Foo f2 = f.Retrieve();
        Console.WriteLine(f2.ToString());
    }
}

Wenn Sie dieses Programm ausführen, wird der Typ -Name von Foo in der Befehlszeile gedruckt. Offensichtlich ist dies ein erfundenes Beispiel, aber vielleicht können Sie etwas Nützlicheres tun, wenn Sie aus einer Datenbank in geladen werden MyBaseClass.Retrieve().

Der Schlüssel ist, eine Einschränkung zu T hinzuzufügen, damit es eine Instanz der Klasse selbst sein muss. Auf diese Weise können Sie die Unterklasse als generischer Typ bei der Unterklasse angeben MyBaseClass<T>.

Ich bin mir nicht ganz sicher, ob dies eine gute Idee ist oder nicht, aber es sieht so aus, als ob es getan werden kann.

Andere Tipps

Sicher. Wenn ich in Ihrem Beispiel möchte, dass meine Foo -Klasse beim Abrufen (...) an den FOO -Kurs zurückgegeben wird:

public class Foo : MyBaseClass<Bar>{}

Hmm, wir verwenden Reflection, um den Klassennamen zu erhalten. Boloader verwendet zweifellos Reflexion, um einige Eigenschaften zu laden. Warum sich nicht vollständig zum Reflexion verpflichten?

Boloader kümmert sich nicht um dieses Spiel von "Rückkehrtyp". Warum sollten wir?

public static class MyBaseClassExtender
{
    public static void Retrieve(this MyBaseClass entity, int ID)
    {
        string className = entity.GetType().Name;
        Database db = DatabaseFactory.CreateDatabase();
        DbCommand dbCommand = db.GetStoredProcCommand(String.Format("{0}s_Retrieve_{0}", className));
        db.AddInParameter(dbCommand, String.Format("@{0}ID", className), DbType.Int32, ID);

        using (IDataReader dr = db.ExecuteReader(dbCommand))
        {
            if (dr.Read())
            {
                BOLoader.LoadDataToProps(this, dr);
            }
        }
    }
}

Dann sagst du nur:

Foo myFoo = new Foo();
myFoo.Retrieve(2);

Nein, es ist nicht so, denn was Sie wirklich brauchen, um in der Klassendefinition so etwas zu tun:

public class MyBaseClass<T> : T

Was derzeit mit Generika nicht möglich ist.

Was Sie tun müssen, ist die Fabrik von dem zu trennen, was die Fabrik erzeugt (Sie benötigen eine separate Klasse, die T erstellt, und dann sollten Sie Helfermethoden bereitstellen, um an T und möglicherweise Erweiterungsmethoden zu arbeiten).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top