• Visitors can check out the Forum FAQ by clicking this link. You have to register before you can post: click the REGISTER link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below. View our Forum Privacy Policy.
  • Want to receive the latest contracting news and advice straight to your inbox? Sign up to the ContractorUK newsletter here. Every sign up will also be entered into a draw to WIN £100 Amazon vouchers!

Generic Class Constraints .NET

Collapse
X
  •  
  • Filter
  • Time
  • Show
Clear All
new posts

    Generic Class Constraints .NET

    Much browsing and gnashing of teeth hasn't got me a solution so I thought I'd come here and both get some sensible answers and general good natured derision for good measure.

    Anyway, I am trying to produce a base class for an object which must be initialised. I want to inherit it and a factory method to get instances. For good measure it's VS2005 and .NET 2.0

    [It's all to do with some standards that are nominally required to be adhered to and visibility outside the class or containing classes (i.e. in the rest of the application - or that portion of it in the current assembly. It's a bit challenging given things can see the private methods of their outer nested classes but not vice versa other classes (within the outer class) can't see them and may need to. Ok if the classes are private but as soon as they become public one can't scope them to restrict the bits that aren't supposed to be, so wrappers have to be produced etc. /rant over]

    Anyway I want to write:-

    Module Module1

    Sub Main()
    Dim summat As x = x.GetNew("aaaaa")
    Dim summat1 As y = y.GetNew("bbbbb")
    End Sub

    End Module

    And I have x and y:-

    Class x : Inherits BaseInitialisedObject(Of x, String)

    Dim x As String = "WWWW"

    End Class

    Class y : Inherits BaseInitialisedObject(Of y, String)

    Dim x As String = "xxxxxWWWW"

    End Class

    And their base class:-

    MustInherit Class BaseInitialisedObject(Of T As {BaseInitialisedObject(Of T, TInitParams), New}, TInitParams)

    Shared Function GetNew(ByVal params As TInitParams) As T
    Dim newObj As New T
    If Not newObj._Init(params) Then
    'Throw New InvalidOperationException("Initialisation Failed")
    End If
    Return newObj
    End Function

    Protected Sub New()

    End Sub

    Private Function _Init(ByVal params As TInitParams) As Boolean

    End Function
    End Class

    Now, the above does what I expect it to but:-

    - I don't understand why I need to constrain the type parameter on the class. I mean it must be one of those since it is being inherited (to be fair it just look damn ugly, but I wonder about efficiency).

    - I can remove the constrain, but then the shared method will have to have the constraint added and this cannot be inferred in the consumer code. i.e. I have to explicity specify it in the call to GetNew

    - Of course if I could invoke a parametered constructor I could take a different approach and only ever serve up valid ones (I might be able to do this with activator]. The shared method does do this, to a point. But all somebody has to do is add a public constructor and the can get as many invalid object as they like. [I could work around this by adding private state to the class definition, but I would have to lock to make it thread safe during construction and throw in the protected constructor when detecting this]

    - Further I would prefer to find a different way of specifying the parameters for the init method so I don't have to define the type in the class definition.

    Essentially I am just trying to protect from misuse by the consumers.

    #2
    Ah I see the problem. You are missing the line numbers.. I suggest you start at 10 and go up in 10 point increments to allow you to slot further code in later if need be... I've started fixing it for you in the sample below but you'll have to do the rest...

    10 Module Module1

    20 Sub Main()
    30 Dim summat As x = x.GetNew("aaaaa")
    40 Dim summat1 As y = y.GetNew("bbbbb")
    50 End Sub

    60 End Module

    and so on....

    Hope that helped.
    'CUK forum personality of 2011 - Winner - Yes really!!!!

    Comment


      #3
      Originally posted by ASB View Post
      Anyway I want to write:-

      Module Module1
      I think I see your problem. This is invalid C# syntax!

      Comment


        #4
        I was all for helping but saw it was vb... Threw up in my mouth and decided to leave you to it

        Comment


          #5
          unhelpful lot. it all the same really. just visualise the curly braces ;-)

          I think I'm probably only going to be able to solve it with activator to verify there is a constructor of the the correct type and the call that but still messy.

          I don't really want to declare an interface since they could cast to it and call the init method again and I don't want that.

          Bah' Humbug.

          Comment


            #6
            Originally posted by ASB View Post

            I think I'm probably only going to be able to solve it with activator to verify there is a constructor of the the correct type and the call that but still messy.

            I don't really want to declare an interface since they could cast to it and call the init method again and I don't want that.
            I got a semi on reading that.
            'CUK forum personality of 2011 - Winner - Yes really!!!!

            Comment


              #7
              Ewwwwwwwwwww
              First Law of Contracting: Only the strong survive

              Comment


                #8
                Isn't that exactly what interfaces are for? Expose public methods while hiding all the private guff?

                But at the end of the day if a consumer has access to you code they can do as they please anyway.

                Comment


                  #9
                  If you are worried about consumers calling Init again, why not have a private flag which is set when Init is called. If Init is called again on an object, throw an InvalidOperationException("Init already called, object is initialised and cannot be initialised again. Please create a new object.").

                  Using interfaces is the way to go, for testability, mocking and dependency injection reasons if nothing else.
                  First Law of Contracting: Only the strong survive

                  Comment


                    #10
                    Well, yes anybody can do pretty much what they want with reflection.

                    Using an interface would not solve the issue, it is then the case that the implementer must force that behaviour (though I suppose I could use a base class they inherit and then call out to a virtual method, the restriction can then be in the non overridable base class method).

                    However, this whole exercise in futility is to try and demonstrate, with justification, why the assorted standards being proposed are not actually workable. Another one is that objects must conform to a close pattern. Well, ok, but can't actually force anybody to implement it.

                    The only point it can be detected in this environment is when the object is finalized, and this of course is too late since nothing at all can be done by then.

                    Comment

                    Working...
                    X