Tech Off Thread

78 posts

Extensia

Back to Forum: Tech Off
  • User profile image
    exoteric

    How about a place to collect nice and useful extension methods (and possibly argue their utility etc.)

    I'm not going to show the definition(s) but here's how to use it

     eventsButton.Enabled = false; this.TryCatchFinally ( () => OrderActions.RequestEvents(session, max), xs => { DatabindEvents(xs); }, ex => MessageBox.Show(ex.Message, "Error"), () => eventsButton.Enabled = true ); 

    This approach is lacking in some departments but it looks safe and is exceptionally easy to use. It takes care of asynchronous computation and continuation on the UI thread, as well as handling exceptions on the UI thread as well.  Sure this can be monadified into further blissfullness.

     

  • User profile image
    ido.ran

    Hi,

    I've been trying to use this technic but it's not all gold.

    The problem is that some actions compose of calls which some needs to be in a background thread yet some need to be on the UI thread. How do you think of solving this problem?

  • User profile image
    Adam​Speight2008

    Get a bitmap representation of a control.

    <System.Runtime.CompilerServices.Extension()> _
     Public Function ToBitmap(ByRef c As Windows.Forms.Control) As Image
      Dim bmp As New Bitmap(c.Width, c.Height)
      c.DrawToBitmap(bmp, New Rectangle(0, 0, c.Width, c.Height))
      Return bmp
     End Function
    

     

    Set properties across threads.

    <System.Runtime.CompilerServices.Extension()> _
     Public Sub CrossThreadSet(Of t)(ByRef [Control] As Control, _
                                     ByRef PropertyName As String, _
                                     ByRef Value As t)
      Dim PInfo As Reflection.PropertyInfo = [Control].GetType.GetProperty(PropertyName)
      If PInfo Is Nothing Then Exit Sub
      If [Control].InvokeRequired Then
       [Control].Invoke(New Delegare_CrossThreadSet(Of t)(AddressOf CrossThreadSet), _
                        New Object() {[Control], PropertyName, Value})
      Else
       PInfo.SetValue([Control], Value, Nothing)
      End If
     End Sub
     Public Delegate Sub Delegare_CrossThreadSet(Of t)(ByRef [Control] As Control, _
                                                       ByRef PropertyName As String, _
                                                       ByRef Value As t)
    

    Usage

    Me.Lbl_Name.CrossThreadSet(of String)("Text","Hello") 
    Me.ProgressBar1.CrossThreadSet(Of Integer)("Value",10)
    

  • User profile image
    exoteric

    ido.ran said:

    Hi,

    I've been trying to use this technic but it's not all gold.

    The problem is that some actions compose of calls which some needs to be in a background thread yet some need to be on the UI thread. How do you think of solving this problem?

    In actual fact it's a "hack". It does not support things like progress indication. This is why I want to look at possible monadic solutions for better composability. The technique shown is very coarse-grained, but you can still synchronize with the UI in the normal way if you need to, e.g.

     public static void Do(this Control control, Action action) { if (control.InvokeRequired) control.Invoke(action); else action(); } 

    But I'm working on composability atm.

  • User profile image
    Sven Groot

    AdamSpeight2008 said:

    Get a bitmap representation of a control.

    <System.Runtime.CompilerServices.Extension()> _
     Public Function ToBitmap(ByRef c As Windows.Forms.Control) As Image
      Dim bmp As New Bitmap(c.Width, c.Height)
      c.DrawToBitmap(bmp, New Rectangle(0, 0, c.Width, c.Height))
      Return bmp
     End Function
    

     

    Set properties across threads.

    <System.Runtime.CompilerServices.Extension()> _
     Public Sub CrossThreadSet(Of t)(ByRef [Control] As Control, _
                                     ByRef PropertyName As String, _
                                     ByRef Value As t)
      Dim PInfo As Reflection.PropertyInfo = [Control].GetType.GetProperty(PropertyName)
      If PInfo Is Nothing Then Exit Sub
      If [Control].InvokeRequired Then
       [Control].Invoke(New Delegare_CrossThreadSet(Of t)(AddressOf CrossThreadSet), _
                        New Object() {[Control], PropertyName, Value})
      Else
       PInfo.SetValue([Control], Value, Nothing)
      End If
     End Sub
     Public Delegate Sub Delegare_CrossThreadSet(Of t)(ByRef [Control] As Control, _
                                                       ByRef PropertyName As String, _
                                                       ByRef Value As t)
    

    Usage

    Me.Lbl_Name.CrossThreadSet(of String)("Text","Hello") 
    Me.ProgressBar1.CrossThreadSet(Of Integer)("Value",10)
    

    Why are you using ByRef with all the parameters? In general, use ByVal unless you absolutely require ByRef, which is not the case in the samples you provided. Definitely don't use ByRef for the "this" parameter in an extension method, that's just weird.

  • User profile image
    Adam​Speight2008

    Sven Groot said:
    AdamSpeight2008 said:
    *snip*

    Why are you using ByRef with all the parameters? In general, use ByVal unless you absolutely require ByRef, which is not the case in the samples you provided. Definitely don't use ByRef for the "this" parameter in an extension method, that's just weird.

    ByVal creates a copy of the parameter.

    In the CrossThreadSet the sub-routine can recursively call itself, if I used ByVal that be the third copy.

    Using ByRef this is only one copy.

     

    It easily overriden by enclosing the parameter with parentheses (Brackets).

  • User profile image
    exoteric

    ido.ran said:

    Hi,

    I've been trying to use this technic but it's not all gold.

    The problem is that some actions compose of calls which some needs to be in a background thread yet some need to be on the UI thread. How do you think of solving this problem?

    Actually, still waiting for Reactive LINQ, then all this is probably obsolete.

  • User profile image
    Sven Groot

    AdamSpeight2008 said:
    Sven Groot said:
    *snip*

    ByVal creates a copy of the parameter.

    In the CrossThreadSet the sub-routine can recursively call itself, if I used ByVal that be the third copy.

    Using ByRef this is only one copy.

     

    It easily overriden by enclosing the parameter with parentheses (Brackets).

    ByVal creates a copy of the parameter.

    No, it does not. What you're saying is true for C(++), but not for .Net.

     

    Reference types (classes) are never copied. Only a reference is ever passed around, hence the name. If you use ByRef, you are actually passing a reference to the reference, a double indirection. Value types (basic types like Integer, structs, enums) are copied, but even there I'd only use ByRef if the structure is very large.

  • User profile image
    Adam​Speight2008

    Sven Groot said:
    AdamSpeight2008 said:
    *snip*

    No, it does not. What you're saying is true for C(++), but not for .Net.

     

    Reference types (classes) are never copied. Only a reference is ever passed around, hence the name. If you use ByRef, you are actually passing a reference to the reference, a double indirection. Value types (basic types like Integer, structs, enums) are copied, but even there I'd only use ByRef if the structure is very large.

    That what I said. (Could have be worded slightly better)

    The data in the ByVal parameter is a copy

    See MSDN Doc

     

    My belief it is ByVal by default to protect the typical vb programmer from themselves.

    I would prefer to option to change the default in the ide.

  • User profile image
    Sven Groot

    AdamSpeight2008 said:
    Sven Groot said:
    *snip*

    That what I said. (Could have be worded slightly better)

    The data in the ByVal parameter is a copy

    See MSDN Doc

     

    My belief it is ByVal by default to protect the typical vb programmer from themselves.

    I would prefer to option to change the default in the ide.

    The data in the ByVal parameter is a copy.

    That is only true for value types. It is not true for reference types! The MSDN link you give says the same thing.

     

    All the parameters in your example are reference types (except for the generic type, which could potentially be a value type). Therefore there is no reason whatsoever to use ByRef.

  • User profile image
    Adam​Speight2008

    Sven Groot said:
    AdamSpeight2008 said:
    *snip*

    That is only true for value types. It is not true for reference types! The MSDN link you give says the same thing.

     

    All the parameters in your example are reference types (except for the generic type, which could potentially be a value type). Therefore there is no reason whatsoever to use ByRef.

    I think your confused.

    A Double is a Value Type

    A String is a Reference Type

    I think of passing;-

     ByRef as using the original which is rewritable.

     ByVal as new copy of (which happens to contain the same data.) so you do what ever you like to it as it get disposed on exit the sub.

      Unless you use it as the return value in a function. (behind the scenes the compiler secretly moves to the correct scope.)

  • User profile image
    Sven Groot

    AdamSpeight2008 said:
    Sven Groot said:
    *snip*

    I think your confused.

    A Double is a Value Type

    A String is a Reference Type

    I think of passing;-

     ByRef as using the original which is rewritable.

     ByVal as new copy of (which happens to contain the same data.) so you do what ever you like to it as it get disposed on exit the sub.

      Unless you use it as the return value in a function. (behind the scenes the compiler secretly moves to the correct scope.)

    No, you're confused.

     

    Your ToBitmap function takes one parameter, a Control, which is a reference type. CrossThreadSet takes three parameters, Control, which is a reference type, String, which is a reference type, and T, which could be either depending on the generic type parameter used.

     

    They are all reference types (except possibly T). Therefore, they are not copied. Therefore, there is no reason to use ByRef uness you wish to change what object it points to, which you're not doing.

     

    The copy argument only holds for value types, and even then the benefit is marginal unless the value type involved is very large.

     

    EDIT: From the MSDN page you linked to:
    "For reference types, only the pointer to the data is copied (four bytes on 32-bit platforms, eight bytes on 64-bit platforms)."

  • User profile image
    littleguru

    Sven Groot said:
    AdamSpeight2008 said:
    *snip*

    No, you're confused.

     

    Your ToBitmap function takes one parameter, a Control, which is a reference type. CrossThreadSet takes three parameters, Control, which is a reference type, String, which is a reference type, and T, which could be either depending on the generic type parameter used.

     

    They are all reference types (except possibly T). Therefore, they are not copied. Therefore, there is no reason to use ByRef uness you wish to change what object it points to, which you're not doing.

     

    The copy argument only holds for value types, and even then the benefit is marginal unless the value type involved is very large.

     

    EDIT: From the MSDN page you linked to:
    "For reference types, only the pointer to the data is copied (four bytes on 32-bit platforms, eight bytes on 64-bit platforms)."

    Sven is right on this topic. Value types are copied. Reference types are not! For the reference type only the pointer (which is a value type in the end) is copied. The instance of the reference type is not copied.

  • User profile image
    Charles

    The idea of a community driven source of useful extension methods would itself be useful. I'm assuming that's the point of this thread? How would this work, practically?

     

    C

  • User profile image
    Adam​Speight2008

    littleguru said:
    Sven Groot said:
    *snip*

    Sven is right on this topic. Value types are copied. Reference types are not! For the reference type only the pointer (which is a value type in the end) is copied. The instance of the reference type is not copied.

    Sven Groot & littleguru.
    You're argued your cases well and you've changed the way I'll think about it the future.
     <shaking fist> damn you vb6 </shaking fist>
    I add to create a diagram to convince myself.
    Notes
     ][ represent the parameter/method boundary,
    --> Object can flow in
    <-- Object can flow out
    ByVal
     ClassObj -->][   

    Inside function/sub :
      ClassObj.foo -->][<--

    ByRef
     ClassObj -->][<--  Can be altered to different object/Nothing

    Inside function/sub:

      ClassObj.foo -->][<--
       
    On doing the diagram, I wondered how I could do.
     
    ByVal

     ClassObj -->][
    Inside function/sub :

      ClassObj.foo -->][

     

    ByRef
     ClassObj -->][

    Inside function/sub :

      ClassObj.foo -->][

    Where it object is effectly read only, irrespective of the setters.

  • User profile image
    Sven Groot

    AdamSpeight2008 said:
    littleguru said:
    *snip*

    Sven Groot & littleguru.
    You're argued your cases well and you've changed the way I'll think about it the future.
     <shaking fist> damn you vb6 </shaking fist>
    I add to create a diagram to convince myself.
    Notes
     ][ represent the parameter/method boundary,
    --> Object can flow in
    <-- Object can flow out
    ByVal
     ClassObj -->][   

    Inside function/sub :
      ClassObj.foo -->][<--

    ByRef
     ClassObj -->][<--  Can be altered to different object/Nothing

    Inside function/sub:

      ClassObj.foo -->][<--
       
    On doing the diagram, I wondered how I could do.
     
    ByVal

     ClassObj -->][
    Inside function/sub :

      ClassObj.foo -->][

     

    ByRef
     ClassObj -->][

    Inside function/sub :

      ClassObj.foo -->][

    Where it object is effectly read only, irrespective of the setters.

    Where it object is effectly read only, irrespective of the setters.

    There is no general way to do this in .Net. You could clone the object (if it implements ICloneable) and pass the clone, or create a read-only wrapper (e.g. List<T> supports this, whic List<T>.AsReadOnly()). If you're looking for something as simple as C++'s const parameters, that is not possible in .Net.

  • User profile image
    Adam​Speight2008

    AdamSpeight2008 said:
    littleguru said:
    *snip*

    Sven Groot & littleguru.
    You're argued your cases well and you've changed the way I'll think about it the future.
     <shaking fist> damn you vb6 </shaking fist>
    I add to create a diagram to convince myself.
    Notes
     ][ represent the parameter/method boundary,
    --> Object can flow in
    <-- Object can flow out
    ByVal
     ClassObj -->][   

    Inside function/sub :
      ClassObj.foo -->][<--

    ByRef
     ClassObj -->][<--  Can be altered to different object/Nothing

    Inside function/sub:

      ClassObj.foo -->][<--
       
    On doing the diagram, I wondered how I could do.
     
    ByVal

     ClassObj -->][
    Inside function/sub :

      ClassObj.foo -->][

     

    ByRef
     ClassObj -->][

    Inside function/sub :

      ClassObj.foo -->][

    Where it object is effectly read only, irrespective of the setters.

    I know these are useless extension but it illustrates why I thought they were copies.

    <System.Runtime.CompilerServices.Extension()> _
     Public Sub MakeNothing(ByRef o As Object)
      o = Nothing
     End Sub
     <System.Runtime.CompilerServices.Extension()> _
    Public Sub DoNothing(ByVal o As Object)
      o = Nothing
     End Sub
    

    Using the first would change the input and second wouldn't.

  • User profile image
    Adam​Speight2008

    Sven Groot said:
    AdamSpeight2008 said:
    *snip*

    There is no general way to do this in .Net. You could clone the object (if it implements ICloneable) and pass the clone, or create a read-only wrapper (e.g. List<T> supports this, whic List<T>.AsReadOnly()). If you're looking for something as simple as C++'s const parameters, that is not possible in .Net.

    I was thinking of a sub that updated the contents on a form, it sole purpose.  No processing / calcution just update the form contents.

    No way of intercepting the set?

     

    What  about?

    Public Class ReadOnlyObj(Of T As Class)
     Protected m_obj As T
     Public Sub New(ByVal obj As T)
      m_obj = obj
     End Sub
     Public ReadOnly Property Obj() As T
      Get
       Return m_obj
      End Get
     End Property
    End Class
     
    <System.Runtime.CompilerServices.Extension()> _
      Public Function makeReadOnly(Of T As Class)(ByVal obj As T)
      Return New ReadOnlyObj(Of T)(obj)
     End Function
    

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.