Why can't I do XYZ in C#?
First off I'm not a language lawyer, or an expert. I am only sharing some of the impressions I've gotten from working with the real language designers.
Eric Wilson asked why C# doesn't allow you to call static methods using instance pointers. My answer would be two-fold:
- C# is very explicit. There's generally one and only one way to do a lot of things that in C/C++ had many ways. Likewise whenever there was a C/C++ language construct that was often mis-used, misunderstood, or just confusing, the language guys tried very hard to make C# impossible to mis-use, misunderstand, or get confused. This is such an example, see reason #2.
- This is confusing to someone who reads the code. If they don't have the definition of the method nearby, they won't know it's static and thus doesn't need a valid instance pointer (which Eric's sample code lacks). Likewise some readers might try and assume that some sort of polymorphic virtual call might happen if the instance pointer is actually some sub class.
Orangy asked why he can't derive from Delegates. The short answer here is that it's a runtime restriction. The runtime deals very intimately with delegates, and as such has some heavy requirements on them. However, you can accomplish the same semantics with a little extra coding. Basically create an intermediate class that holds a weak reference (this is not new in v2, just new to me, thanks Dmitriy) to the real delegate, then pass the intermediate delegate to the real event:
// warning untested pseudo codesealed class WeakDelegate { public EventHandler MakeWeakDelegate(EventHandler realDelegate) { return new EventHandler(new WeakDelegate(realDelegate).WeakInvoke); } private volatile WeakReference realDelegate; // volatile so it is thread safe private WeakDelegate(EventHandler realDelegate) { this.realDelegate = new WeakReference(realDelegate); } private void WeakInvoke(object sender, EventArgs args) { EventHandler eh = this.realDelegate.Target as EventHandler; if (eh != null) { eh.Target(sender, args); } }}
That's all for today.
--Grant
[Corrected the code and some comments in response to Dmitriy's criticism]
Comments
- Anonymous
December 07, 2004
My real question regarding delegates is why I can't seem to create a delegate function whose definition contains a parameter that matches in the inheritance chain of the defined event delgate...
Ok, that was really confusing to explain... It's much easier to explain in a code example:
public class MyEventArgs : EventArgs
{
// Extra Event Arguments...
}
public class MyClass
{
public delegate void MyDelegate( object sender, MyEventArgs e );
public event MyDelegate SomeEvent;
public void MyEventHandler( object sender, System.EventArgs e )
{
// Do Something
}
public MyClass()
{
// Compile error here
SomeEvent += new MyDelegate(MyEventHandler);
}
I should be allowed to pass a MyEventArgs object to a function that takes an EventArgs object since MyEventArgs derives from EventArgs. This is useful when I in fact intend to ignore e, but will use the same logic for multiple events whose signatures don't match exactly.
Obviously there are simple enough work arounds, but still, this would be convenient. - Anonymous
December 08, 2004
if (eh.IsAlive)
{
eh.Target(sender, args);
}
This doesn't seem to be thread safe - Anonymous
December 08, 2004
EventHandler.IsAlive???
WeakReference new in v2??? - Anonymous
December 08, 2004
You're correct. That's what I get for posting code without fully testing it. - Anonymous
December 08, 2004
What Nick is askign for is commonly called Contravariance or Covariance (I can never keep the two strait). IIRC the language designers have wanted to add this, but the current CLR doesn't so they can't. But keep looking for it. I think some non-MS languages that target the CLR have found work-arounds. - Anonymous
December 08, 2004
I have beta of Whidbey and it supports contravariance and covariance of delegates.
Support seems to be in CLR - Anonymous
December 09, 2004
2Grant: Well, this implementation (when fixed) does help very little. It replaces long-live refrence to potentially huge object with long-live reference to WeakDelegate object. The references are as follows: Publisher -> strong ref -> WeakDelegate -> weak ref -> EventHandler -> strong ref -> Subscriber. So, when Subscriber is subject to be GCed, we have WeakDelegate's hanging around. One could replace publisher->weakdelegate strong reference with another weak one but this could be done with direct link from publisher to subscriber and requires publisher to know about "weak subscribers". This can help sometimes, though. Of course, I thought about this method ;)