2

最近、 try catchブロックを適切に使用せず、残念ながらtry ... catchブロックを重大な状況で使用し、例外エラーをすべて無視して作業している開発者について投稿しました。私に大きな心臓の痛みを引き起こします。これは、彼らがこれを行ったコードの数千の​​セクションの1つの例です(特に重要ではないいくつかのコードが省略されています:

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

私の目には、これは絶対に議論の余地があり、潜在的な問題が発生した場合にユーザーに通知することはありません。多くの人がOOPは悪であり、複数のレイヤーを追加するとコードの行数とプログラムの複雑さが増し、コードの保守に問題が発生する可能性があると言うことを知っています。私のプログラミングのバックグラウンドの多くは、個人的には、この分野でほぼ同じアプローチを取っています。以下に、このような状況で通常コーディングする方法の基本構造を示します。これは、私のキャリアの中で多くの言語で行ってきましたが、この特定のコードはC#です。しかし、以下のコードは、私がオブジェクトをどのように使用するかについての良い基本的な考え方であり、私にとってはうまくいくようですが、これはかなり賢いプログラミング鉱山の良い情報源なので、これを再評価する必要があるかどうか知りたいです私がしているテクニック 長年使用してきました。主な理由は、今後数週間で、外部委託された開発者からのあまり良くないコードに突入し、コードの巨大なセクションを変更することになるからです。なるべくやりたいです。長いコード参照でごめんなさい。

// *******************************************************************************************
/// <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;
        }
    }

結論として、私の質問は、複数のレイヤーと継承されたクラスで物事を複雑にしすぎているのでしょうか、それとも私の古い概念がまだうまく機能していて安定しているのでしょうか?これらのことを達成するためのより良い方法はありますか?ビジネスオブジェクトやデータ層(データ層ではなく表示されていますが、基本的にすべてのストアドプロシージャ呼び出しを保持しています)。ええ、別の開発者は、ページの後ろにある* .aspx.csコードに必要なものを直接入力できるのに、なぜ私が物事を階層化する努力をするのかと私に尋ねました。そうすれば、1,000行を超えるコードを楽しむことができます。後ろ。ここでいくつかのアドバイスは何ですか?

4

6 に答える 6

1

コードの最初のビットから次のビットへのジャンプは非常に大きいです。複雑なビジネス オブジェクト レイヤーが必要かどうかは、アプリのサイズによって異なります。少なくとも、私たちのポリシーでは、例外は処理された場所でログに記録されます。ユーザーにどのように提示するかはあなた次第ですが、必要に応じて開発者がより多くの情報を取得できるように、ログを保持することが不可欠です。

于 2008-10-24T22:37:33.183 に答える
1

NHibernate のような ORM の使用を検討したことがありますか? 車輪を再発明しても意味がありません。

私にとって、これはコードの匂いです:

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

ブラケットが多すぎます。

C# のような言語でアクティブ レコード パターンを使用すると、単体テストが難しいため、常に失敗に終わることがわかりました。

于 2008-10-24T21:19:45.977 に答える
0

具体的なクラスの代わりに抽象基本クラスを使用することは可能ですか? これにより、ランタイム例外ではなく、開発時にメソッドの実装が強制されます。

ここで同意する最良のコメントは、その時点で回復できる例外のみを処理する必要があるダンスからのものです。他の人を捕まえて再投げするのが最善の方法です(めったに行われないと思いますが)。また、それらがログに記録されていることを確認してください.... :)

于 2008-10-25T06:09:22.273 に答える
0

私の経験則は、処理できるエラーのみをキャッチするか、ユーザーに何か役立つものを提供して、ユーザーが同じことを再度行った場合に、それが機能する可能性が高いようにすることです。データベースの例外をキャッチします。ただし、使用されているデータに関するエラーにさらに情報を追加するだけです。それから私はそれを投げ直します。一般的にエラーを処理する最善の方法は、UI スタックの最上位ではなく、どこでもエラーをキャッチすることです。エラーを処理するページを 1 つ用意し、global.asax を使用してそのページにルーティングするだけで、ほぼすべての状況に対応できます。ステータス コードを使用することは、まったく時代遅れです。COMの名残です。

于 2008-10-24T22:49:29.713 に答える
0

Page_Load イベントで例外をキャッチしないのはなぜですか? あなたが予想し、対処方法を知っている例外もありますが、その他の例外はグローバル例外ハンドラで処理する必要があります。

于 2008-10-24T22:19:50.850 に答える
0

あなたのエラー処理の方法は非常に時代遅れのようです。新しい例外を作成し、少なくともコールスタックがあるように例外から継承するだけです。次に、nlog や log4net などでログを記録する必要があります。これは 2008 年なので、ジェネリックを使用します。そうすれば、キャストを大幅に減らす必要があります。

Aそして、誰かが前に言ったようにORMを使用してください。車輪の再発明を試みないでください。

于 2008-10-25T13:01:51.327 に答える