c# 2.x feature requests

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Don't know if this is the correct forum for this, but here goes..

- independent access level modifiers for property get and set members
eg. public get, protected set, set provides validation / thread sync
facilities
- default class member access set to protected rather than private
- automagic thread concurrency managment for the add / remove event members
eg. automagic management of thread concurrency issues associated with +=
and -= event overloads

...

anyone else care to comment

-- Steve
 
steve said:
Don't know if this is the correct forum for this, but here goes..

- independent access level modifiers for property get and set members
eg. public get, protected set, set provides validation / thread sync
facilities

That's already in the beta.
- default class member access set to protected rather than private

Thankfully that's *not* in the beta. Protected access should be used
more rarely than private access (particularly for fields). In addition,
if you make something private but it should actually be protected,
you're likely to find out at compile time. The other way round, you'll
never know until something uses the unintended access...
- automagic thread concurrency managment for the add / remove event members
eg. automagic management of thread concurrency issues associated with +=
and -= event overloads

What exactly would you want it to do? Currently it locks on "this" and
I believe it will at least be *allowed* to lock on a private member
variable instead if the compiler decides to.
 
Thanks for the feedback.

Jon Skeet said:
That's already in the beta.

good


Thankfully that's *not* in the beta. Protected access should be used
more rarely than private access (particularly for fields). In addition,
if you make something private but it should actually be protected,
you're likely to find out at compile time. The other way round, you'll
never know until something uses the unintended access...

fair enough for fields. But invariably I find that I want to call methods
of ancestors. Yes I agree that it is best to encapsulate as much as
possible, I guess it's just a bit harder when your in a hurry.. ; )
What exactly would you want it to do? Currently it locks on "this" and
I believe it will at least be *allowed* to lock on a private member
variable instead if the compiler decides to.

I googled up this commentary on event race conditions

http://blogs.msdn.com/csharpfaq/archive/2004/03/19/93082.aspx

This is what I have been doing to avoid probs when wiring / unwiring
delegates. comments?

#region SomethingHappenedEvent

object SomethingHappenedEventLock = new object();
protected event SomethingHappenedEvent mSomethingHappened;
public event SomethingHappenedEvent SomethingHappened
{
add
{
lock (SomethingHappenedEventLock)
{
if (mSomethingHappened == null)
{
// Acquire any shared resources required for processing event
}
mSomethingHappened += value;
}
}
remove
{
lock (SomethingHappenedEventLock)
{
mSomethingHappened -= value;
if (mSomethingHappened == null)
{
// Release any shared resources required for processing event
}
}
}
}

protected virtual void OnSomethingHappened()
{
lock (SomethingHappenedEventLock)
{
if (mSomethingHappened != null)
{
mSomethingHappened(this, new SomethingHappenedEventArgs());
}
}
}

#endregion

 
steve said:
Thanks for the feedback.



good

Yes, it's great. However I'll always miss the friend modifier in C++ or as
done in Delphi.
fair enough for fields. But invariably I find that I want to call methods
of ancestors. Yes I agree that it is best to encapsulate as much as
possible, I guess it's just a bit harder when your in a hurry.. ; )

Hehe, I've never been in such a hurry. Also, I would avoid coding virtual
classes when in panic. =)

Happy Coding
- Michael S
 
Hello Michael,
Yes, it's great. However I'll always miss the friend modifier in C++
or as done in Delphi.

"friend" is available through internal methods, which will thus be available
throughout your entire assembly. I know, this allows all the code in that
assembly to reach those methods, but they will at least be available to you,
and not to any code outside of the assembly.
 
steve said:
fair enough for fields. But invariably I find that I want to call methods
of ancestors. Yes I agree that it is best to encapsulate as much as
possible, I guess it's just a bit harder when your in a hurry.. ; )

I think it would be a really bad idea for a language change to
encourage rushed programming.

Personally, I don't used protected methods very often - but then I
favour composition over inheritance in the first place.
I googled up this commentary on event race conditions

http://blogs.msdn.com/csharpfaq/archive/2004/03/19/93082.aspx

This is what I have been doing to avoid probs when wiring / unwiring
delegates. comments?

Sure - it's broken in a different way. You're maintaining the lock for
the whole of the time the event is running. Given that events in UIs
often involve Control.Invoke, you could easily end up with a deadlock.

See http://www.pobox.com/~skeet/csharp/lockchoice.shtml
 
Great ideas, Steve. Keep them coming!

Private data is a misnomer... I haven't tried it in C#, but in C++ you'd
have no problem breaking into private data with a few casts and pointer
arithmetic. It helps if you have the class definition and an understanding of
the memory mapping.

So, I see the real reason for defaulting to private as that it promotes
encapsulation, making derived classes more proper, and your class free from
worrying about what those derived classes could be doing easily that they
shouldn't.

As for more automagic delegate support, I agree in general. I posted a
comment titled "C# Language Specification - Delegates", which deals with some
of the stuff.

I have problems with third-party components that generate exceptions which
they don't rethrow, and who attach to events but don't remove those event
handlers when they are disposed. Hence, it's not something I can easily
overcome unless it's made automagic.
 
Jon said:
What exactly would you want it to do? Currently it locks on "this" and
I believe it will at least be *allowed* to lock on a private member
variable instead if the compiler decides to.

Jon, I've seen you mention this before and it's in your lock choice
article as well. I don't doubt that you are correct about that. That
is, that the compiler locks on "this" automatically if you do not
include the add/remove code for events. But, where did you learn about
this? I assumed that there wasn't any synchronization going on because
I didn't find any mention of it in the C# specification or other
documentation.

Brian
 
Marshal [DirectX MVP 2003] <MarshalDirectXMVP2003
@discussions.microsoft.com said:
Great ideas, Steve. Keep them coming!

Private data is a misnomer... I haven't tried it in C#, but in C++ you'd
have no problem breaking into private data with a few casts and pointer
arithmetic. It helps if you have the class definition and an understanding of
the memory mapping.

You can't do that in C#. You can break the privacy using reflection,
but only if you've got the appropriate permissions.

<snip>
 
Brian Gideon said:
Jon, I've seen you mention this before and it's in your lock choice
article as well. I don't doubt that you are correct about that. That
is, that the compiler locks on "this" automatically if you do not
include the add/remove code for events. But, where did you learn about
this? I assumed that there wasn't any synchronization going on because
I didn't find any mention of it in the C# specification or other
documentation.

It's in the C# spec (the ECMA version) in section 17.7.1:

<quote>
When compiling a field-like event, the compiler automatically creates
storage to hold the delegate, and creates accessors for the event that
add or remove event handlers to the delegate field. 2 In order to be
thread-safe, the addition or removal operations are done while holding
the lock (§15.12) on the containing object for an instance event, or
the type object (§14.5.11) for a static event.
</quote>
 
Jon said:
It's in the C# spec (the ECMA version) in section 17.7.1:

<quote>
When compiling a field-like event, the compiler automatically creates
storage to hold the delegate, and creates accessors for the event that
add or remove event handlers to the delegate field. 2 In order to be
thread-safe, the addition or removal operations are done while holding
the lock (§15.12) on the containing object for an instance event, or
the type object (§14.5.11) for a static event.
</quote>

Ah...thanks. I knew it had to be somewhere.
 
Sure - it's broken in a different way. You're maintaining the lock for
the whole of the time the event is running. Given that events in UIs
often involve Control.Invoke, you could easily end up with a deadlock.

See http://www.pobox.com/~skeet/csharp/lockchoice.shtml

Hee he. Wise you are master grasshopper. Hadn't thought of synchronised
context switches.. will add the little mods you highlighted in the
lockchoice page. Cheers.
 
How about this Jon? Have a look at the OnSomethingHappened method.

#region SomethingHappenedEvent

object SomethingHappenedEventLock = new object();
protected event SomethingHappenedEvent mSomethingHappened;
public event SomethingHappenedEvent SomethingHappened
{
add
{
lock (SomethingHappenedEventLock)
{
if (mSomethingHappened == null)
{
// Acquire any shared resources required for processing event
}
mSomethingHappened += value;
}
}
remove
{
lock (SomethingHappenedEventLock)
{
mSomethingHappened -= value;
if (mSomethingHappened == null)
{
// Release any shared resources required for processing event
}
}
}
}

protected virtual void OnSomethingHappened()
{
// New Code thanks to Jon Skeet
//

SomethingHappenedEvent SomethingHappened;
lock (SomethingHappenedEventLock)
{
SomethingHappened = mSomethingHappened;
}

// Correct me if i'm wrong here, but...
//
// If we get a context switch here and a thread
// detaches a handler from the SomethingHappened event
// the handler will still *receive* one last event..

if SomethingHappened != null)
{
SomethingHappened(this, new SomethingHappenedEventArgs());
}

// Old Code
//
// This can deadlock if the =- or += overloads are called by a
// synchronised thread indirection, eg. Control.Invoke

// lock (SomethingHappenedEventLock)
// {
// if (mSomethingHappened != null)
// {
// mSomethingHappened(this, new SomethingHappenedEventArgs());
// }
}
}

#endregion
 
steve said:
How about this Jon? Have a look at the OnSomethingHappened method.

Well, it's still not clear to me why you've got all the resource
acquisition stuff there - after all, if you don't need the resources
until an event occurs, that's when you should acquire them, and you
should release them immediately afterwards.

You're right that there's still a race condition - but if you consider
the unsubscription (or extra subscription) to occur at "the same time"
as raising the event, then it's just as correct to process the
subscription differences after the event as before it.
 
Thanks again Jon

The resource allocation / deallocation areas are just me brainstorming. It
may make sense to only allocate resources when there is an eventhandler
plumbed into the system. In other words is there any point consuming these
resources when there are no event handlers for the event.

For instance say the *thing* that sources the event comes through interop.
Furthermore say that this interop thing consumes a shared physical resource,
eg. RS-232 port. It may not make sense for this resource to be consumed when
there are no event handlers plumbed into the event... Hence the resource
allocation / deallocation.

Thoughts?

Ciao

Steve
 
Here's another one

constant arrays, ie.

const byte[] E2PROM_DATA_DEF = {0x01, 0x02, 0x03, 0x04, ...};
 
steve said:
Thanks again Jon

The resource allocation / deallocation areas are just me brainstorming. It
may make sense to only allocate resources when there is an eventhandler
plumbed into the system. In other words is there any point consuming these
resources when there are no event handlers for the event.

For instance say the *thing* that sources the event comes through interop.
Furthermore say that this interop thing consumes a shared physical resource,
eg. RS-232 port. It may not make sense for this resource to be consumed when
there are no event handlers plumbed into the event... Hence the resource
allocation / deallocation.

Thoughts?

Yes, that sounds fairly reasonable. It's not something I've ever had to
do, and I'd suggest that it should be the exception rather than the
rule, but it could be handy sometimes.
 
use can use "static readonly" instead :)


steve said:
Here's another one

constant arrays, ie.

const byte[] E2PROM_DATA_DEF = {0x01, 0x02, 0x03, 0x04, ...};

steve said:
Don't know if this is the correct forum for this, but here goes..

- independent access level modifiers for property get and set members
eg. public get, protected set, set provides validation / thread sync
facilities
- default class member access set to protected rather than private
- automagic thread concurrency managment for the add / remove event
members
eg. automagic management of thread concurrency issues associated with
+=
and -= event overloads

..

anyone else care to comment

-- Steve
 
Back
Top