Frage

Vor kurzem ich einen Beitrag gemacht über die Entwickler ich arbeite mit nicht blockiert try catch richtig verwenden und Unfortuantely try ... catch-Blöcke in kritischen Situationen mit und alle zusammen den Ausnahmefehler zu ignorieren. was mir große Herzschmerzen. Hier ist ein Beispiel für eine der mehrere tausend Codeabschnitte, die sie taten dies (einige Codes links heraus, dass nicht particuarly Frage:

public void AddLocations(BOLocation objBllLocations)
{
    try
    {
        dbManager.Open();
        if (objBllLocations.StateID != 0)
        {
             // about 20 Paramters added to dbManager here
        }
        else
        {
           // about 19 Paramters added here
        }
        dbManager.ExecuteNonQuery(CommandType.StoredProcedure, "ULOCATIONS.AddLocations");
    }
    catch (Exception ex)
    {
    }
    finally
    {
        dbManager.Dispose();
    }
}

Das ist absolut ekelhaft, in meinen Augen, und benachrichtigen den Benutzer nicht, falls einige potenzielle Problem aufgetreten ist. Ich weiß, dass viele Leute sagen, dass OOP böse ist, und dass das Hinzufügen von mehreren Schichten erhöhen die Anzahl der Codezeilen und die Komplexität des Programms, mit dem Code maintainence zu möglichen Problemen führen. Ein großer Teil meiner Programmierung Hintergrund, ich persönlich habe fast den gleichen Ansatz in diesem Bereich gemacht. Im Folgenden werde ich eine Grundstruktur der Art und Weise aufgeführt heraus habe ich normalerweise Code in einer solchen Situation, und ich habe dies in meiner Karriere viele Sprachen accross getan, aber diese spezielle Code ist in C #. Aber der Code unten ist eine gute Grundidee, wie ich die Objekte verwenden, scheint es für mich zu arbeiten, aber da dies eine gute Quelle für einige ziemlich inteligent Programmierung Minen ist, würde Ich mag wissen, ob ich sollte diese neu bewerten Technik, die ich seit so vielen Jahren verwendet haben. Vor allem, weil in den nächsten Wochen werde ich von den ausgelagerten Entwicklern und Ändern von großen Code-Abschnitten in dem nicht so guten Code stürzen werden. Ich mag es so gut wie möglich tun. sorry für den langen Code Referenz.

// *******************************************************************************************
/// <summary>
/// Summary description for BaseBusinessObject
/// </summary>
/// <remarks>
/// Base Class allowing me to do basic function on a Busines Object
/// </remarks>
public class BaseBusinessObject : Object, System.Runtime.Serialization.ISerializable
{
    public enum DBCode
    {   DBUnknownError,
        DBNotSaved,
        DBOK
    }

    // private fields, public properties
    public int m_id = -1;
    public int ID { get { return m_id; } set { m_id = value; } }
    private int m_errorCode = 0;
    public int ErrorCode { get { return m_errorCode; } set { m_errorCode = value; } }
    private string m_errorMsg = "";
    public string ErrorMessage { get { return m_errorMsg; } set { m_errorMsg = value; } }
    private Exception m_LastException = null;
    public Exception LastException { get { return m_LastException; } set { m_LastException = value;} }

    //Constructors
    public BaseBusinessObject()
    {
        Initialize();
    }
    public BaseBusinessObject(int iID)
    {
        Initialize();
        FillByID(iID);
    }
    // methods
    protected void Initialize()
    {
        Clear();
        Object_OnInit();
        // Other Initializable code here
    }
    public void ClearErrors()
    {
        m_errorCode  = 0; m_errorMsg = ""; m_LastException = null;
    }

    void System.Runtime.Serialization.ISerializable.GetObjectData(
         System.Runtime.Serialization.SerializationInfo info, 
        System.Runtime.Serialization.StreamingContext context)
    {
      //Serialization code for Object must be implemented here
    }
    // overrideable methods
    protected virtual void Object_OnInit()     
    {
        // User can override to add additional initialization stuff. 
    }
    public virtual BaseBusinessObject FillByID(int iID)
    {
        throw new NotImplementedException("method FillByID Must be implemented");
    }
    public virtual void Clear()
    {
        throw new NotImplementedException("method Clear Must be implemented");
    }
    public virtual DBCode Save()
    {
        throw new NotImplementedException("method Save Must be implemented");
    }
}
// *******************************************************************************************
/// <summary>
/// Example Class that might be based off of a Base Business Object
/// </summary>
/// <remarks>
/// Class for holding all the information about a Customer
/// </remarks>
public class BLLCustomer : BaseBusinessObject
{
    // ***************************************
    // put field members here other than the ID
    private string m_name = "";
    public string Name { get { return m_name; } set { m_name = value; } }
    public override void Clear()
    {
        m_id = -1;
        m_name = "";
    }
    public override BaseBusinessObject FillByID(int iID)
    {
        Clear();
        try
        {
            // usually accessing a DataLayerObject, 
            //to select a database record
        }
        catch (Exception Ex)
        {
            Clear();
            LastException = Ex;
            // I can have many different exception, this is usually an enum
            ErrorCode = 3;
            ErrorMessage = "Customer couldn't be loaded";
        }
        return this;
    }
    public override DBCode Save()
    {
        DBCode ret = DBCode.DBUnknownError;
        try
        {
            // usually accessing a DataLayerObject, 
            //to save a database record
            ret = DBCode.DBOK;
        }
        catch (Exception Ex)
        {
            LastException = Ex;
            // I can have many different exception, this is usually an enum
            // i do not usually use just a General Exeption
            ErrorCode = 3;
            ErrorMessage = "some really weird error happened, customer not saved";
            ret = DBCode.DBNotSaved;
        }
        return ret;
    }
}
// *******************************************************************************************
// Example of how it's used on an asp page.. 
    protected void Page_Load(object sender, EventArgs e)
    {
        // Simplifying this a bit, normally, I'd use something like, 
        // using some sort of static "factory" method
        // BaseObject.NewBusinessObject(typeof(BLLCustomer)).FillByID(34);
        BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34);
        if (cust.ErrorCode != 0)
        {
            // There was an error.. Error message is in 
            //cust.ErrorMessage
            // some sort of internal error code is in
            //cust.ErrorCode

            // Give the users some sort of message through and asp:Label.. 
            // probably based off of cust.ErrorMessage
            //log can be handled in the data, business layer... or whatever
            lab.ErrorText = cust.ErrorMessage;
        }
        else
        {
            // continue using the object, to fill in text boxes, 
            // literals or whatever. 
            this.labID = cust.ID.toString();
            this.labCompName = cust.Name;
        }
    }

Unterm Strich ist meine Frage: Bin ich über die Dinge mit den muliple Schichten, und die geerbten Klassen oder mein altes Konzept arbeitet bebilderte noch verkompliziert gut und stabil? Gibt es eine bessere Art und Weise jetzt Tage, diese Dinge zu erreichen? Soll ich nur gerade SQL-Aufrufe von dem asp.net Seite Code mache hinter Seiten als fellow Pflegerische Entwickler vorschlug (obwohl die letzte Lösung mich eklig macht fühlen), statt durch ein Business-Objekt zu gehen, und die Datenschicht (Datenschicht nicht gezeigt, aber im Grunde hält alle gespeicherten proc Anrufe). Ja, hat ein anderer Entwickler mich fragen, warum ich durch die Anstrengung der Schichtung Dinge gehen, wenn Sie können eingeben, was Sie gerade in einem * aspx.cs Code hinter Seite benötigen, und dann kann ich die Freuden der über 1k Zeilen Code haben hinter. Was einige Ratschläge hier?

War es hilfreich?

Lösung

Haben Sie ein ORM wie NHibernate betrachtet verwenden? Es gibt keinen Punkt in neu zu erfinden das Rad.

Für mich ist das ein Code Geruch:

BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34);

Zu viele Klammern!

Ich habe festgestellt, dass mit dem Active Record in einer Sprache wie C # endet immer in Tränen, weil es zu Unit-Test schwer (er) ist.

Andere Tipps

Der Sprung aus dem ersten Stück Code auf den nächsten ist riesig. Ob eine komplizierte Business-Objekt-Schicht notwendig ist, hängt von der Größe der App in Frage abhängen. Zumindest wenn unsere Politik ist, dass Ausnahmen eingeloggt sind, wo sie behandelt werden. Wie Sie für den Anwender bis zu Ihnen Protokollen aber ist von wesentlicher Bedeutung, so dass Entwickler weitere Informationen erhalten können, wenn nötig.

Warum fangen nicht nur die Ausnahme in dem Ereignis Page Load? Einige Ausnahme, die Sie vielleicht erwarten und wissen, wie zu behandeln, andere Ausnahmen sollten von einem globalen Exception-Handler behandelt werden.

Meine Faustregel nur fangen Fehler, die ich verarbeiten kann oder der Benutzer etwas Nützliches geben, so dass, wenn sie tun, was es war, dass sie schon wieder getan, es ist wahrscheinlich, für sie zu arbeiten. Ich fange Datenbank Ausnahmen; aber nur ein paar mehr Informationen auf den Fehler über die Daten hinzuzufügen, verwendet werden; dann wieder werfe ich es. Der beste Weg, um Fehler im Allgemeinen zu behandeln ist nicht, sie zu fangen überhaupt überall, aber an der Spitze des UI-Stack. Nur mit einer Seite, die Fehler und mit Hilfe des global.asax auf dem Weg zu handhaben, um es fast alle Situationen umgeht. Status-Codes ist auf jeden Fall alle zusammen aus der Mode. Es ist ein Überbleibsel von COM.

Ist es möglich, eine abstrakte Basisklasse statt einer konkreten Klasse zu bedienen? dies würde die Umsetzung Ihrer Methoden zur Entwicklungszeit zwingen, anstatt Laufzeit Ausnahmen.

Der beste Kommentar hier vereinbaren mit von Tänzen, wo man nur Ausnahmen behandeln, sollen Sie von zu diesem Zeitpunkt wiederherstellen können. Fangen andere und Erneutes Auslösen ist die beste Methode (obwohl ich denke, seine selten getan). Stellen Sie außerdem sicher, dass sie angemeldet sind ....:)

Ihr Weg von Fehlerbehandlung scheint sehr veraltet. So stellen Sie einen neuen exeption und erben von exeption diese Weise können Sie die Aufrufliste zumindest haben. Dann sollten Sie mit so etwas wie nlog oder log4net anmelden. Und das ist das Jahr 2008 so Generika verwenden. Sie werden viel zu tun haben, weniger auf diese Weise gegossen wird.

und ein ORM verwenden, wie jemand vorher gesagt. Versuchen Sie nicht, das Rad neu zu erfinden.

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