Помощь в настройке класса другими разработчиками - PullRequest
1 голос
/ 12 сентября 2010

ОБНОВЛЕНО: Добавлен пример кода, чтобы помочь прояснить.

Привет, чувствую, что это не должно быть так сложно, но я думаю, что просто не знаю подходящего названия для того, что я пытаюсьделать.Я имею дело с проектом ASP.net.

Концепция довольно проста: у меня есть библиотека, которая предоставляет некоторые функции ecomm.Один класс в библиотеке содержит функции для расчета налога.Один класс в библиотеке вращается вокруг заголовка корзины.Этот класс используется веб-проектом.

Будет такой метод, как carthead.SaveCart.Внутри SaveCart, он должен будет вызывать tax.CalculateTax

Что мне нужно сделать, это выяснить способ, позволяющий carthead.SavCart всегда иметь доступ к определенной функции, такой как tax.CalculateTax (например, чтофункция всегда должна быть доступна для библиотеки).

Однако затем я хочу разрешить кому-либо создавать другую версию метода tax.CalculateTax.

Я пытался кое-что сделать спереопределяемый базовый класс, но я обнаружил, что хотя он и переопределяет базовый класс налогов в веб-проекте, он вызывает только переопределенную версию налогового класса, когда я звоню из веб-проекта.Я не могу превратить класс налога в интерфейс, так как когда я это делаю, я не могу определить результаты tax.CalculateTax как список (потому что в этом случае t является интерфейсом, а не фактическим классом) - этот список долженбыть использованным методом carthead.SaveCart.

Поэтому, когда вы шагаете по коду, вы обнаруживаете, что когда веб-проект вызывает метод carthead.SaveCart, метод carthead.SaveCart не имеет доступа к переопределенному коду из веб-проекта.... и приводит к вызову неопределяемой версии метода tax.CalculateTax.

Я уверен, что что-то упустил, но я даже не уверен, что именно я должен исследовать иликаково именно правильное имя для того, что я пытаюсь выполнить.

Для того, чтобы свести его к нулю, мне нужно иметь возможность переопределить метод и вызвать переопределенную версию метода из не переопределяемых методов.в библиотеке.

Может кто-нибудь указать мне, что я испортил или на что мне следует обратить внимание?

ОБНОВЛЕНИЕ: Добавлены некоторые фрагменты кода, чтобы помочь прояснить:

Вот фрагмент рассматриваемого класса CartHeader:

Public Class CartHeader

, остальные классы пропущены

Public Function UpdateCartStep2(ByVal CartNo As Long, ByVal Username As String, _
ByVal PmtMethod As String, ByVal ShipMethod As String, _
ByVal ShipComplete As Boolean, ByVal ShipCost As Double, _
ByVal ShipInstr As String, Optional ByVal TaxGroup As String = "", _
Optional ByVal PickupLoc As String = "", _
Optional ByVal FuelSurcharge As Double = 0, _
Optional ByVal Misc As String = "", _
    Optional ByVal TaxThisSomeTaxOrder As Boolean = False, _
    Optional ByVal ShipToID As Long = 0, _
    Optional ByVal ShipToZip As String = "", _
    Optional ByVal mCustCode As String = "", _
    Optional ByVal CustTax As Tax = Nothing) As Integer
    '=================>
    'note that the last parameter is new which is what we're currently using to pass in the customtax class so that we can consume it inside this method
    '==================>


    If IsNothing(CustTax) Then
        CustTax = New Tax
    End If

    '6-29-08 this stored proc was updated to allow for fuel surcharge
    'added fuel surcharge parameter

    Dim Resultval As Integer
    Dim strConnect As New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString)
    Dim SqlCommand As New SqlCommand("sp_UpdateCartStep2", strConnect)

    Try

        Dim SubTotalAmt As Double
        SubTotalAmt = GetCartSubTotal(CartNo)

        GetCartHeader(CartNo)

        Dim CartTax As Double

        Dim SystemTypeID As Integer = CInt(ConfigurationManager.AppSettings("SystemTypeID").ToString)

        Select Case SystemTypeID
            Case 1

                If profile.AllowTerms = False Then
                    CartTax = CalcTax(SubTotalAmt, ShipCost, FuelSurcharge, m_Ship_State_Province)
                Else
                    CartTax = 0
                End If
            Case 2
                '6-29-08 added to figure fuel surcharge
                'Dim CustTax As New Tax
                'Dim CustCode As String = System.Web.HttpContext.Current.Profile("CustCode")
                Dim lCustTax As New List(Of Tax)

                '=========================>
                'note that this part of the header must always call into the calctax method.
                'it should be able to call the custom method if it has been defined.
                lCustTax = CustTax.wa_cc_CalcTax(mCustCode, ShipToID, SubTotalAmt, ShipCost, FuelSurcharge, CStr(m_Ship_State_Province), CStr(ShipToZip))
                '==========================>


                For Each ct As Tax In lCustTax
                    CartTax += ct.Tax
                Next
                'CartTax = CalcTax(SubTotalAmt, ShipCost, FuelSurcharge, m_Ship_State_Province, TaxGroup)

        End Select

        SqlCommand.CommandType = CommandType.StoredProcedure
        strConnect.Open()

        SqlCommand.Parameters.AddWithValue("@CartNo", SqlDbType.BigInt).Value = CartNo
        SqlCommand.Parameters.AddWithValue("@Username", SqlDbType.VarChar).Value = Username
        SqlCommand.Parameters.AddWithValue("@PmtMethod", SqlDbType.VarChar).Value = PmtMethod
        SqlCommand.Parameters.AddWithValue("@ShipMethod", SqlDbType.VarChar).Value = ShipMethod
        SqlCommand.Parameters.AddWithValue("@ShipCompleteFlag", SqlDbType.Bit).Value = ShipComplete
        SqlCommand.Parameters.AddWithValue("@ShipCost", SqlDbType.Money).Value = ShipCost
        SqlCommand.Parameters.AddWithValue("@Tax", SqlDbType.Money).Value = CartTax
        SqlCommand.Parameters.AddWithValue("@ShipInstr", SqlDbType.VarChar).Value = ShipInstr
        SqlCommand.Parameters.AddWithValue("@PickupLoc", SqlDbType.VarChar).Value = PickupLoc
        SqlCommand.Parameters.AddWithValue("@FuelSurcharge", SqlDbType.Float).Value = FuelSurcharge

        '1-30-08 Changed to accomodate holding the carrier number when selecting collect freight
        'required modification of the sp_UpdateCartStep2 stored procedure.
        SqlCommand.Parameters.AddWithValue("@Misc3", SqlDbType.VarChar).Value = Misc3

        SqlCommand.ExecuteNonQuery()
        Resultval = 0
    Catch ex As Exception
        Resultval = -1
        System.Web.HttpContext.Current.Trace.Write(ex.Message)
    Finally
        strConnect.Close()
    End Try

    Return Resultval
End Function

Конечный класс


Этоучебный класс мы используем в качестве базового класса ... он имеет переопределенный wa_cc_calctax, если вызовы базовой функции не применяются.

Public Class Tax


Private _Tax As Double
Public Property Tax() As Double
    Get
        Return _Tax
    End Get
    Set(ByVal value As Double)
        _Tax = value
    End Set
End Property

Private _TaxRate As Double
Public Property TaxRate() As Double
    Get
        Return _TaxRate
    End Get
    Set(ByVal value As Double)
        _TaxRate = value
    End Set
End Property


Private _TaxDesc As String
Public Property TaxDesc() As String
    Get
        Return _TaxDesc
    End Get
    Set(ByVal value As String)
        _TaxDesc = value
    End Set
End Property


Private _TaxGroupID As String
Public Property TaxGroupID() As String
    Get
        Return _TaxGroupID
    End Get
    Set(ByVal value As String)
        _TaxGroupID = value
    End Set
End Property


Private _TaxJurisdictionID As String
Public Property TaxJurisdictionID() As String
    Get
        Return _TaxJurisdictionID
    End Get
    Set(ByVal value As String)
        _TaxJurisdictionID = value
    End Set
End Property



Private _TaxCustCode As String
Public Property TaxCustCode() As String
    Get
        Return _TaxCustCode
    End Get
    Set(ByVal value As String)
        _TaxCustCode = value
    End Set
End Property


Private _TaxFreight As Boolean
Public Property taxFreight() As Boolean
    Get
        Return _TaxFreight
    End Get
    Set(ByVal value As Boolean)
        _TaxFreight = value
    End Set
End Property




Public Enum TaxableStatus
    All
    None
    some
End Enum


''' <summary>
''' It will first try to figure out if we're shipping to the same zip as the ship to
''' if it is the same, then we'll use the ship-tos tax group
''' if it is different, then we'll go to manual tax.
''' in manual tax, the customer record is reviewed and the class_1id field is interogated.
''' The code selected tells us what states the customer is taxable for.
''' If we are in those states, then the customer tax group is chosed based on the state.
''' </summary>
''' <param name="mCustCode"></param>
''' <param name="mShipToID"></param>
''' <param name="SubTotalAmt"></param>
''' <param name="FreightCost"></param>
''' <param name="FuelSurcharge"></param>
''' <param name="m_Ship_State_Province"></param>
''' <param name="m_Zip"></param>
''' <param name="TaxGroup"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Overridable Function wa_cc_CalcTax(ByVal mCustCode As String, _
                       ByVal mShipToID As String, _
                       ByVal SubTotalAmt As Double, _
                     ByVal FreightCost As Double, _
                    ByVal FuelSurcharge As Double, _
                    ByVal m_Ship_State_Province As String, _
                    ByVal m_Zip As String, _
                     Optional ByVal TaxGroup As String = "") As List(Of Tax)

    'do some 'normal' tax calcs.


    Return New List(Of Tax)

End Function

Конечный класс


Это класс CustomTax, которыйпереопределяет функцию wa_cc_calctax:

Public Class CustomTax

Inherits Tax


''' <summary>
''' It will first try to figure out if we're shipping to the same zip as the ship to
''' if it is the same, then we'll use the ship-tos tax group
''' if it is different, then we'll go to manual tax.
''' in manual tax, the customer record is reviewed and the class_1id field is interogated.
''' The code selected tells us what states the customer is taxable for.
''' If we are in those states, then the customer tax group is chosed based on the state.
''' </summary>
''' <param name="mCustCode"></param>
''' <param name="mShipToID"></param>
''' <param name="SubTotalAmt"></param>
''' <param name="FreightCost"></param>
''' <param name="FuelSurcharge"></param>
''' <param name="m_Ship_State_Province"></param>
''' <param name="m_Zip"></param>
''' <param name="TaxGroup"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Overrides Function wa_cc_CalcTax(ByVal mCustCode As String, _
                       ByVal mShipToID As String, _
                       ByVal SubTotalAmt As Double, _
                     ByVal FreightCost As Double, _
                    ByVal FuelSurcharge As Double, _
                    ByVal m_Ship_State_Province As String, _
                    ByVal m_Zip As String, _
                     Optional ByVal TaxGroup As String = "") As List(Of Tax)
    Dim lTX As New List(Of Tax)

    Dim mUseP21Tax As Boolean = True
    If mShipToID <= 0 Then
        mUseP21Tax = False
    End If

    If FreightCost <= 0 Then
        FreightCost = 0
    End If

    Dim tx As New CustomTax
    Dim ZipMatch As Boolean
    If mShipToID > 0 Then
        'we're dealing with a selected ship to so we should see if it all still matches
        ZipMatch = CheckZipAgainstShipTo(m_Zip, mCustCode, mShipToID)
    Else
        'this item is not a selected ship-to so no need to look for a match
        ZipMatch = False
    End If

    If ZipMatch = True Then

        lTX = LookupTaxForShipTo(mCustCode, mShipToID, SubTotalAmt, FreightCost)
    Else
        lTX = LookupManualTax(mCustCode, m_Ship_State_Province, SubTotalAmt, FreightCost, , m_Zip)


    End If


    Return lTX

End End End Class


Итак, проблема в том, что: 1) Если я сделаю класс Tax интерфейсом или абстрактным классом,затем я должен «создать» его как новый класс внутри класса cartheader, чтобы я мог вызвать метод wa_cc_lookupclass.2) Когда мы создаем новый класс налога внутри класса cartheader, то мы не обновляем новый пользовательский экземпляр класса налога, и поэтому пользовательский код не используется.

Цель состоит в следующем:1) Укажите базовый класс Tax, который имеет «нормальную» функциональность.2) Разрешить пользователю переопределять класс налога в папке app_code веб-приложения, чтобы создать новую логику для расчета налога.Он будет по-прежнему иметь те же входные и выходные сигнатуры, что и оригинал.3) Метод cartheader.UpdateCartStep2 должен иметь возможность доступа к функции wa_cc_calctax из базового или переопределенного пользовательского класса (если он переопределен).

В этом примере мы явно взломали его и передали в пользовательский.версия налогового класса (CustomTax) в метод UpdateCartStep2 в качестве параметра.Это был обходной путь, который мы внедрили, основываясь на предложении здесь ... однако мы знаем, что это не «правильный» способ сделать это.

Ответы [ 4 ]

1 голос
/ 12 сентября 2010

Я могу придумать два варианта.

  1. Сделайте класс вашей корзины абстрактным, а метод CalculateTax - абстрактным.Это заставит других разработчиков реализовать собственный метод CalculateTax и расширить базовый класс.

  2. Передать параметр в метод SaveCart (или конструктор класса), который предоставляет информацию о том, как рассчитать налогНапример, делегат или функция.Затем метод SaveCart вызывает этого делегата для выполнения части 'CalculateTax'.

0 голосов
/ 13 декабря 2010

После обсуждения с Microsoft (и платы) они решили, что единственное, что можно было сделать в этих обстоятельствах, - это передать экземпляр нового объекта или функцию предиката в класс.Это потому, что класс скомпилирован в dll, а внутри dll будет ссылаться на базовый класс, определенный внутри dll ... Поэтому мы создали опцию для передачи переопределенного экземпляра базового класса ... есть проверка кодачтобы увидеть, является ли это переданное в экземпляре пустым, и если оно является новым в базовом классе.Если он был предоставлен, тогда мы используем переданный экземпляр вместо обновления нового базового класса.

Надеюсь, это поможет кому-то еще.

0 голосов
/ 12 сентября 2010

Перечитав вопрос и ваши комментарии, я вижу, что вы хотите решить 2 вещи:

  1. как заставить метод базового класса вызываться
  2. каксделать, чтобы сторонний предоставленный класс включался в систему

Далее ответьте на приведенные выше вопросы, но я бы предпочел вместо этого:

Определить ITaxCalculator (Вы можете найти лучшее имя ...).Получите ITaxCalculator в методе, который требует расчета.Предоставьте DefaultTaxCalculator или что-то подобное, если применимо, и либо сделайте так, чтобы клиентский вызов передал вам это, либо используйте его по умолчанию, если параметр калькулятора равен нулю.

Если ваша кодовая база затрудняет передачу этого в процесс, определите TaxCalculatorFactory, например, CartFactory ниже, и только TaxCalculatorFactory.Create () /, если применимо по умолчанию, следует установить в DefaultTaxCalculator.

Получив экземпляр ITaxCalculator, вы вызываете taxCalculator.CartTax (currentCart), чтобы получить налог на корзину.

Таким образом, точка расширения гораздо более сфокусирована, что, по моему мнению, упрощает задачуконец.


Ответьте на оригинальные вопросы:

Для 1 вы не можете принудительно вызвать его напрямую.Решение подкласса вызывать base.TheSameMethod (), что позволяет ему размещать некоторую логику до и / или после выполнения базового метода.

Вы можете обойти это, не имея логику, которую хотите всегдавызываться в методе, который переопределяет.Что вы делаете, это вызываете 1 или 2 метода, которые могут быть переопределены, для CartSave вы можете определить OnCartSaving и OnCartSaved.CartSave не может быть переопределен, но так как он вызывает те 2, которые могут быть переопределены, вы предоставляете точки расширения.

Для 2, я думаю, что это совершенно новый вопрос, и есть разные способы решить его.,

Если вам нужно контролировать, когда создается экземпляр, вы можете создать Factory, которая может быть настроена клиентским кодом (или через .config приложения) для использования их класса.Как это делает инфраструктура для разных поставщиков данных.

Простым вариантом может быть предоставление статического свойства с помощью Func, которое клиентский код может установить для такой функции:

CartFactory.Create =() => new MySpecificCart ();

Если это asp.net, вы можете поместить это в запуск приложения в global.asax.Затем, где вам нужно создать экземпляр корзины, вы можете: CartFactory.Create ();


Оригинальный ответ - игнорировать / Сначала я не получил вопрос:

Простодумаю, но кажется, что вы не объявляете метод в определенном классе с ключевым словом override .

Если вышеприведенное имеет место, вы, вероятно, получили предупреждение от компилятора.

0 голосов
/ 12 сентября 2010

Что-то вроде следующего:

abstract class BaseCartOperations
{
    public void SaveCart ()
    {

        // ...

        CalculateTax();
    }


    protected void CalculateTax ()
    {
        // Base Tax Stuff
        CalculateTaxInternal();
    }


    // Force implementation
    protected abstract void CalculateTaxInternal ();
}

?(или некоторые их вариации).

...