Posted By: exoteric | Sep 2nd @ 5:10 AM
page 1 of 3
Comments: 50 | Views: 978
exoteric
exoteric
I : Next<I>

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.

 

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?

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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)

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

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.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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).

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

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.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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.

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

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.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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.)

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

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)."

littleguru
littleguru
<3 Seattle

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.

Charles
Charles
Welcome Change

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

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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.

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

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.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

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

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

The object returned from the property Obj is not read only. The ReadOnly keyword only means the property has no setter. You'd have to wrap the object entirely, every single method call, and disallow those that change the state of the object. This is what ReadOnlyCollection does.

 

And even a ReadOnlyCollection only wraps the collection. The objects in the collecton are still not read only and can be modified.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

That to me that not a readonly collection, more of fixed collection.

Read Only to me uggest you can't alter anything, for example a music cd is a read only collection of music.

AdamSpeight2008
AdamSpeight2008
The Bandito Coder

On the quest on of the readonly object. This is only a theory .

Could it be implemented with a new class which essenstially the same as object but with the difference that FieldSetter doesn't set?

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

To try to steer this thread back to its original topic, here's an extension method I came up with that lets you use foreach to enumerate the lines of a file, without having to use File.ReadAllLines (which reads the entire file into memory and is therefore not a good idea on large files):

 

public static class TextReaderExtensions
{
    public static IEnumerable<string> EnumerateLines(this TextReader reader)
    {
        if( reader == null )
            throw new ArgumentNullException("reader");

        string line;
        while( (line = reader.ReadLine()) != null )
        {
            yield return line;
        }
    }
}

 

You can then do this:

using( StreamReader reader = File.OpenText("myfile.txt") )
{
    foreach( string line in reader.EnumerateLines() )
    {
        // Do something with the line
    }
}

 

Which looks cleaner than the usual while-loop approach. Smiley

TommyCarlier
TommyCarlier
I want my scalps!

I have a suggestion to improve your code: split EnumerateLines in a public method that validates the argument and a private method that implements the functionality. With your code, the entire method is lazily invoked and the argument validation code will not be called when EnumerateLines is invoked, but when the first MoveNext is called. When you split it, the arguments are validated immediately.

public static class TextReaderExtensions
{
  public static IEnumerable<string> EnumerateLines(this TextReader reader)
  {
    if( reader == null )
      throw new ArgumentNullException("reader");

    return EnumerateLinesCore(reader);
  }

  private static IEnumerable<string> EnumerateLinesCore(TextReader reader)
  {
    string line;
    while( (line = reader.ReadLine()) != null )
    {
      yield return line;
    }
  }
}

EDIT: struggling with the code snippet formatting.

TommyCarlier
TommyCarlier
I want my scalps!

Here's a simple one I occasionally use (to avoid having to import System.Globalization each time I need CultureInfo.InvariantCulture):

public static string FormatInvariant(this string format, params object[] args)
{
  if (format == null) throw new ArgumentNullException("format");
  return string.Format(CultureInfo.InvariantCulture, format, args);
}

Used like this:

s = "Date {0:d}, Time {0:t}".FormatInvariant(DateTime.Now);

page 1 of 3
Comments: 50 | Views: 978
Microsoft Communities