Delegates, abstract classes and interfaces

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

Guest

Hi

Consider the following code snipet:

delegate void SomeDelegate(ICollection collection);

void SomeDispatch() {
ArrayList al = new ArrayList();
al.Add("hello");

SomeDelegate sd = new SomeDelegate(SomeMethod);
sd.Invoke(al);
}

void SomeMethod(ArrayList al) {
// do something
Console.Write(al.Count.ToString());
}


I get a compile-time error telling me that I'm not using signature that
matches the delegate. I'm not sure why the runtime doesn't support this, can
anyone explain this one to me. I can sub out an interface for a abstract
class with the same effect.
 
Craig said:
Hi

Consider the following code snipet:

delegate void SomeDelegate(ICollection collection);

void SomeDispatch() {
ArrayList al = new ArrayList();
al.Add("hello");

SomeDelegate sd = new SomeDelegate(SomeMethod);
sd.Invoke(al);
}

void SomeMethod(ArrayList al) {
// do something
Console.Write(al.Count.ToString());
}


I get a compile-time error telling me that I'm not using signature
that matches the delegate. I'm not sure why the runtime doesn't
support this, can anyone explain this one to me. I can sub out an
interface for a abstract class with the same effect.

change
void SomeMethod(ArrayList al) {
into
void SomeMethod(ICollection collection) {

As the delegate method signature you defined contains ICollection as
the type of the parameter, though the method you specified has
ArrayList as the type. This could lead to runtime errors when you pass
an ICollection implementing type which isn't an ArrayList to the
delegate and which then thus creates a runtime exception, something you
don't want to happen, so the compiler checked this for you up front.

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
Hi Frans

Thanks for the reply. I realise if I change the signature of the delegate
to match the function all would be ok.

Here's a snipet of what I want to do:

delegate void SomeDelegate(ICollection collection);

void SomeDispatch(ICollection collection) {
SomeDelegate sd = null;
if(collection is ArrayList) {
sd = new SomeDelegate(SomeMethod);
}
else if (collection is BitAray) {
sd = new SomeDelegate(SomeMethod1);
}

sd.Invoke(collection);
}

void SomeMethod(ArrayList al) {
// do something specific for an ArrayList
Console.Write(al.Count.ToString());
}

void SomeMethod1(BitArray ba) {
// do something specific to a BitArray
Console.Write(ba.Count.ToString());
}

Whether I use an interface or an abstract class in the delegate signature I
fully expected the compiler to reflect the actual passed argument ensuring it
was the correct or derived from the correct type.

Do you think is a reasonable assumption?

Craig
 
Craig said:
Hi Frans

Thanks for the reply. I realise if I change the signature of the delegate
to match the function all would be ok.

Here's a snipet of what I want to do:

delegate void SomeDelegate(ICollection collection);

void SomeDispatch(ICollection collection) {
SomeDelegate sd = null;
if(collection is ArrayList) {
sd = new SomeDelegate(SomeMethod);
}
else if (collection is BitAray) {
sd = new SomeDelegate(SomeMethod1);
}

sd.Invoke(collection);
}

void SomeMethod(ArrayList al) {
// do something specific for an ArrayList
Console.Write(al.Count.ToString());
}

void SomeMethod1(BitArray ba) {
// do something specific to a BitArray
Console.Write(ba.Count.ToString());
}

As you need to query the specific type in your dispatch method anyway,
I would do the needed downcast right there:

namespace ConsoleApplication
{
delegate void SomeDelegateArrayList(ArrayList collection);
delegate void SomeDelegateSortedList(SortedList collection);
class Program
{
static void SomeDispatch(ICollection collection)
{
Delegate sd = new SomeDelegateArrayList(SomeMethodDefault);
if (collection is ArrayList)
{
sd = new SomeDelegateArrayList(SomeMethodArrayList);
}
else if (collection is SortedList)
{
sd = new SomeDelegateSortedList(SomeMethodSortedList);
}

sd.DynamicInvoke(collection);
}
static void SomeMethodArrayList(ArrayList al)
{
// do something
Console.Write(al.Count.ToString());
}
static void SomeMethodSortedList(SortedList sl)
{
// do something
Console.Write(sl.Count.ToString());
}
static void SomeMethodDefault(ICollection al)
{
// do sensible default??
throw new NotImplementedException();
}
static void Main(string[] args)
{
}
}
}

Whether I use an interface or an abstract class in the delegate signature I
fully expected the compiler to reflect the actual passed argument ensuring it
was the correct or derived from the correct type.

Do you think is a reasonable assumption?

Nope. If this would be possible you could do something like this:

namespace ConsoleApplication
{
delegate void SomeDelegate(ICollection collection);
class Program
{
static void SomeDispatch()
{
SortedList sl = new SortedList();
sl.Add("hello", "hello");

SomeDelegate sd = new SomeDelegate(SomeMethod);
sd.Invoke(sl);
}

static void SomeMethod(ArrayList al)
{
// do something
al.AddRange(new int[]{1, 2});// How would that work for a
// sorted list??
}
static void Main(string[] args)
{
}
}
}

The delegate is a contract. It says: "When you have a delegate of this
type, it can work with an ICollection."

Your function has a contract stating: "This function can handle an
ArrayList"

ArrayList is a ICollection, but you can do a lot more with it! So how
should the compiler and/or runtime handle it, especially if all these
bits are defined across different assemblies?

BTW, in classic C++ or Java you would model a delegate using an interface:

interface ISomeDelegate
{
void SomeMethod(ICollection al);
}

and what you expect would look like this:

class SomeDelegate : ISomeDelegate
{
void SomeMethod(ICollection al);
}

which wouldn't compile either.


BTW, it does work the other way round:

namespace ConsoleApplication
{
// delegate taking the specialized type
delegate void SomeDelegate(ArrayList collection);
class Program
{
static void SomeDispatch()
{
ArrayList al = new ArrayList();
al.Add("hello");

SomeDelegate sd = new SomeDelegate(SomeMethod);
sd.Invoke(al);
}
// function that takes the base type
static void SomeMethod(ICollection al)
{
// do something
Console.Write(al.Count.ToString());
}
static void Main(string[] args)
{
}
}
}

HTH,
Andy
 
Hi Craig,

That is because not all ICollection implementations are ArrayList objects.

Consider invoking sd with a SortedList. The delegate signature will support the call, however the concrete method will not.
 
Back
Top