views:

2160

answers:

6

Hi,

I am trying to create a delegate (as a test) for:

Public Overridable ReadOnly Property PropertyName() As String

My intuitive attempt was declaring the delegate like this:

Public Delegate Function Test() As String

And instantiating like this:

Dim t As Test = AddressOf e.PropertyName

But this throws the error:

Method 'Public Overridable ReadOnly Property PropertyName() As String' does not have a signature compatible with delegate 'Delegate Function Test() As String'.

So because I was dealing with a property I tried this:

Public Delegate Property Test() As String

But this throws a compiler error.

So the question is, how do I make a delegate for a property?

A: 

See this link:

http://peisker.net/dotnet/propertydelegates.htm

Graphain
Seems vastly over-baked to me...
Marc Gravell
Yeah I agree :-)
Graphain
A: 

Here's a C# example but all the types are the same:

First create the interface(delegate). Remember, a method that you attach to your delegate must return the same type, and take the same parameters as your delegate's declaration. Don't define your delegate in the same scope as your event.

public delegate void delgJournalBaseModified();

Make an event based on the delegate:

public static class JournalBase {
    public static event delgJournalBaseModified evntJournalModified;
};

Define a method that can be tied to your event that has an interface identical to the delegate.

void UpdateEntryList()
{
}

Tie the method to the event. The method is called when the event is fired. You can tie as many methods to your event. I don't know the limit. It's probably something crazy.

 JournalBase.evntJournalModified += new delgJournalBaseModified(UpdateEntryList);

What happens here is the method is added as a callback for your event. When the event is fired, your method(s) will be called.

Next we make a method that will fire the event when called:

public static class JournalBase {
    public static  void JournalBase_Modified()
    {
    if (evntJournalModified != null)
        evntJournalModified();
    }
};

Then you simply call the method -- JournalBase_Modified() -- somewhere in your code and all methods tied to your event are called too, one after another.

Ice
I didn't vote you down but the question referred to properties
Graphain
Yea... I see that after the fact. Thank you for not voting me down. It looks like I answered without checking the context of the question... Silly me.
Ice
+7  A: 

Re the problem using AddressOf - if you know the prop-name at compile time, you can (in C#, at least) use an anon-method / lambda:

Test t = delegate { return e.PropertyName; }; // C# 2.0
Test t = () => e.PropertyName; // C# 3.0

I'm not a VB expert, but reflector claims this is the same as:

Dim t As Test = Function 
    Return e.PropertyName
End Function

Does that work?


Original answer:

You create delegates for properties with Delegate.CreateDelegate; this can be open for any instance of the type, of fixed for a single instance - and can be for getter or setter; I'll give an example in C#...

using System;
using System.Reflection;
class Foo
{
    public string Bar { get; set; }
}
class Program
{
    static void Main()
    {
        PropertyInfo prop = typeof(Foo).GetProperty("Bar");
        Foo foo = new Foo();

        // create an open "getter" delegate
        Func<Foo, string> getForAnyFoo = (Func<Foo, string>)
            Delegate.CreateDelegate(typeof(Func<Foo, string>), null,
                prop.GetGetMethod());

        Func<string> getForFixedFoo = (Func<string>)
            Delegate.CreateDelegate(typeof(Func<string>), foo,
                prop.GetGetMethod());

        Action<Foo,string> setForAnyFoo = (Action<Foo,string>)
            Delegate.CreateDelegate(typeof(Action<Foo, string>), null,
                prop.GetSetMethod());

        Action<string> setForFixedFoo = (Action<string>)
            Delegate.CreateDelegate(typeof(Action<string>), foo,
                prop.GetSetMethod());

        setForAnyFoo(foo, "abc");
        Console.WriteLine(getForAnyFoo(foo));
        setForFixedFoo("def");
        Console.WriteLine(getForFixedFoo());
    }
}
Marc Gravell
Thanks - Im stuck in .NET 2.0 for a project in question and I'll see if something similar works and feedback here (otherwise could be why the elaborate solution I linked to came about)
Graphain
It appears to work (haven't tested extensively) but I'm wondering if you can help with this problem. I need to get the property without using a hard-coded string. Problem is, I need the PropertyInfo to get the get method and I can't get this from the property addressOf
Graphain
Also thanks for the PropertyInfo approach :-)
Graphain
Thanks for the update - unfortunately VB.NET doesn't support anonymous methods - I guess the only solution is to make a function wrapper for each property and create a delegate for that (pretty much what the reflector code is doing).
Graphain
VB.NET supports lambda expressions (but they must return a value) - http://blogs.msdn.com/wriju/archive/2008/02/05/vb-net-9-0-lambda-expression.aspx
Richard Szalay
+1  A: 

Here is a C#/.NET 2.0 version of Marc Gravell's response:

using System;
using System.Reflection;

class Program
{
 private delegate void SetValue<T>(T value);
 private delegate T GetValue<T>();

 private class Foo
 {
  private string _bar;

  public string Bar
  {
   get { return _bar; }
   set { _bar = value; }
  }
 }

 static void Main()
 {
  Foo foo = new Foo();
  Type type = typeof (Foo);
  PropertyInfo property = type.GetProperty("Bar");

  // setter
  MethodInfo methodInfo = property.GetSetMethod();
  SetValue<string> setValue =
   (SetValue<string>) Delegate.CreateDelegate(typeof (SetValue<string>), foo, methodInfo);
  setValue("abc");

  // getter
  methodInfo = property.GetGetMethod();
  GetValue<string> getValue =
   (GetValue<string>) Delegate.CreateDelegate(typeof (GetValue<string>), foo, methodInfo);
  string myValue = getValue();

  // output results
  Console.WriteLine(myValue);
 }
}

Again, 'Delegate.CreateDelegate' is what is fundamental to this example.

Ray Vega
A: 

This is pretty interesting, but I have noticed that it won't work for structs. In that case, the call to CreateDelegate messes it up, because it expects 'object' for the instance reference and of course .Net will box a struct and send that boxed copy in instead.

The net effect is that the property one then sees or sets pertains to a copy of the original struct.

I can see now way to support this sort of property manipulation on a struct unless one resorts to Emit and CIL.

Hugh Moran
+1  A: 

I just create an helper with pretty good performance : http://thibaud60.blogspot.com/2010/10/fast-property-accessor-without-dynamic.html It don't use IL / Emit approach and it is very fast !