Comparing .NET delegates


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 2 of 2

Thread: Comparing .NET delegates

Hybrid View

  1. #1
    Join Date
    Jan 2005
    Posts
    4

    Comparing .NET delegates

    I'm having some problems comparing delegates. In all sample projects I
    create, I can't get the problem to occur, but there is definitely a problem
    with my production code.

    I can't give all the code, as there's simply too much, but here's the
    general gist:

    I have a connection object which connects to a custom back-end server of one
    type or another. Clients of this connection object send requests via a
    method (e.g. connection.SendRequest()) and one of parameters to this call is
    a callback delegate.

    At a later point, the client may attempt to cancel all the requests specific
    to the delegate that was passed in. It's in this method that I'm doing the
    delegate comparisons. Consistently, the delegates never match, so the
    requests can't be cancelled.

    In the client code, I've tried passing in the method name directly or a
    delegate instance, created with the method as a parameter. I get the same
    results either way.

    When debugging, I notice something strange, and no doubt the cause of the
    problem:

    The stored delegate refers to the actual method to call:
    .Method: the actual method name
    .Target: the actual class name where the method resides

    ...but the delegate passed in, refers to an Invoke method:
    .Method: Invoke
    .Target: the delegate type!

    So, I understand why the comparison is failing. They don't appear to be the
    same delegate at all! But I don't understand why the passed in delegate
    refers to the Invoke method, instead of the actual target method.

    Can someone explain to me what's going on? And moreover, does anyone have a
    solution to the problem?
    Thanks.

  2. #2
    Join Date
    Jan 2005
    Posts
    4
    Here is an excerpt from a discussion in another forum on this same topic. Note, I still haven't resolved the problem.

    Here's the basic structure of the code I'm using. Note, I don't have a problem with this code; it appears to be working as expected. When I run the same sort of
    structure on my code, the delegates are never equal, as described in my first
    post. The problem is, when I'm doing the same sort of thing in my code.

    namespace DelegateTest
    {
    delegate void MyDelegate(int x);

    class Program
    {
    static void Main(string[] args)
    {
    Client client = new Client();
    client.Start();
    }
    }

    class Client
    {
    Connection connection = new Connection();

    public void Callback(int x)
    {
    }

    public void Start()
    {
    MyDelegate myDel = new MyDelegate(Callback);

    connection.SendRequest(myDel);
    connection.SendRequest(Callback);
    connection.CancelRequests(myDel);
    connection.CancelRequests(Callback);
    }
    }

    class Connection
    {
    List<MyDelegate> storedDelegates = new List<MyDelegate>();

    public void SendRequest(MyDelegate del)
    {
    storedDelegates.Add(del);
    // Send request to server
    }

    public void CancelRequests(MyDelegate del)
    {
    Console.WriteLine("Cancel requests:");
    int count = 0;
    foreach (MyDelegate storedDel in storedDelegates)
    {
    count++;
    Console.WriteLine("Delegate: " + count.ToString());
    Console.WriteLine((del == storedDel).ToString());
    Console.WriteLine(del.Equals(storedDel).ToString());
    Console.WriteLine(MyDelegate.Equals(del,
    storedDel).ToString());
    Console.WriteLine(MyDelegate.ReferenceEquals(del,
    storedDel).ToString());
    }
    // Send cancel to the server
    }
    }
    }

    ...And now the discussion:

    > your code is a bit confusing. In one case, you're adding a delegate to the
    > list. In another, you're adding a method:
    >
    > > connection.SendRequest(myDel);
    > > connection.SendRequest(Callback);
    >
    > They are not the same. A delegate is a delegate; a method is a method.

    Yes, I did this on purpose to demonstrate the different ways in which I have tried to resolve the problem. When a parameter to a method is a delegate, .NET allows me to either specify an explicit delegate OR a method matching that delegate as the parameter, as I'm sure you're aware. It seems like .NET 2.0 allows you to treat delegates and methods almost exactly the same.

    I was just trying to test if I would get different results in my comparisons, depending on which method I use (explicit delegate or method name) to call SendRequest().

    > You have not posted your output, so I have no idea what the answer to the
    > following question is:

    My output, I'm sure, would be the same as what you would get compiling and running this code:
    Cancel requests:
    Delegate: 1
    True
    True
    True
    True
    Delegate: 2
    True
    True
    True
    False
    Cancel requests:
    Delegate: 1
    True
    True
    True
    False
    Delegate: 2
    True
    True
    True
    False

    This is expected behavior, so my sample code isn't showing the problem that I'm experiencing. It just illustrates the basic structure of the code I'm debugging.

    > > Any thoughts on why that Invoke is getting in there?
    >
    > What Invoke getting in where?

    Here's the scenario:
    In my actual client code, I call the SendRequest() method a few times, each time passing in the same delegate (or the same method name, when I tried it that way), and then called the CancelRequests() method, passing in that same delegate (or method name) -- exactly like I'm doing in my sample code above.

    In VS, I put a break point in the CancelRequests() method, at the point where the comparison between the passed-in delegate and the stored delegate were compared. The equality comparison between these two was always returning false, depsite the fact that I passed in the actual same delegate to both the SendRequest() and CancelRequests() methods. This is what's puzzling. I'm trying a few different things to get the proper comparison to happen:

    At compile-time, if I try to compare (using any of the equality comparisons mentioned) the passed-in delegate with the stored delegate, I get the following compile-time error:

    The best overloaded method match for 'object.Equals(object, object)' has some invalid arguments: Argument '1': cannot convert from 'method group' to 'object'

    So, that makes sense. This is where the natural .NET facility to treat methods and delegates the same breaks down. But this is in itself is puzzling, because the the stored delegate reference is of the same type. The reference inside the object is a delegate reference, so I don't understand why .NET is now treating it as a method instead, when I'm doing the comparison. The stored reference is in a hash table of request objects, and inside each of those request objects is a delegate reference. That reference is set to what was initialled passed in to SendRequest().

    In an attempt to get around this problem, I create a new, temporary delegate just before the comparison. The method I give as a parameter to the temp delegate constructor is the stored delegate reference from inside the request object.

    When I inspect the two delegates at debug-time, here's what I see:

    Stored delegate (direct reference to it from the hash table):
    Type: my delegate type
    Base: System.MulticastDelegate
    Base: System.Delegate
    Method: Void Callback(int x)
    Target: null

    Passed-in delegate:
    Type: my delegate type
    Base: System.MulticastDelegate
    Base: System.Delegate
    Method: Void Callback(int x)
    Target: null

    They look the same, as far as I can tell. But, remember, I am unable to find a comparison method which will compare these directly and not give compiler errors, since .NET is treating the stored delegate reference as a 'method group' and not a delegate!

    So, as I explained, I wrapped up the stored delegate in a temporary delegate and inspected it at debug time. This is what I get:
    Type: my delegate type
    Base: System.MulticastDelegate
    Base: System.Delegate
    Method: Void Callback(int x)
    Target: Request object

    And a comparison between this and the passed-in delegate fails (I presume) because of the different targets.

    So, in desperation, I ALSO wrapped the passed-in delegate in a seperate temporary delegate. At debug-time it looked like this:
    Type: my delegate type
    Base: System.MulticastDelegate
    Base: System.Delegate
    Method: Void Invoke(int x)
    Target: My delegate type

    So, that's where the Invoke comes in. I assume then that me wrapping the passed-in delegate in a temporary delegate, adds an extra delegate layer, and isn't what I want.

Similar Threads

  1. Microsoft's C++ bigotry
    By Phil Weber in forum .NET
    Replies: 632
    Last Post: 10-01-2003, 12:00 AM
  2. I'm confused !!!
    By cgts in forum .NET
    Replies: 24
    Last Post: 02-28-2003, 03:43 PM
  3. Microsoft gains Visual Studio .NET momentum
    By Patrick Troughton in forum .NET
    Replies: 1
    Last Post: 02-12-2003, 09:31 AM
  4. Replies: 0
    Last Post: 03-20-2002, 05:28 AM
  5. YAG's status report - Feb 21, 2002
    By Seth Grossman [MSFT] in forum .NET
    Replies: 11
    Last Post: 02-28-2002, 01:44 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center