How pass delegate to a method, where delegates are

2019-07-20 10:46发布

问题:

I'm just beginning understanding delegates, I have a class that implemens IDisposable:

public class MyClass : IDisposable
{
  public delegate int DoSomething();

  public int Zero() {return 0;}
  public int One() {return 1;}

  public void Dispose()
  {
    // Cleanup
  }
}

A method (defined in an another class) that is using MyClass:

public class AnotherCLass
{
    public static void UseMyClass(MyClass.DoSomething func)
    {
      using (var mc = new MyClass())
      {
        // Call the delegate function
        mc.func(); // <-------- this is what i should actually call
      }
    }
}

The actual question: how pass the Zero() function to UseMyClass method? Do I have to create an instance of MyClass (I would like to avoid this...)?

public static void main(string[] args)
{
  // Call AnotherClass method, by passing Zero()
  // or One() but without instatiate MyCLass
  AnotherClass.UseMyClass(??????????);
}

回答1:

Because it's an instance method, if you want to call it, you need an instance. That's simply how the CLR works. However, there are two options you could go with:

  • Make the member functions static. If they're as simple as returning a static value, there's no reason for them to be instance methods. However, if you do actually require instance data...
  • Use a singleton instance. This way you don't need to create a new instance every time you want to call your static method.

You can do the latter like this:

public class MyClass
{
    private static MyClass singletonInstance;
    public static MyClass SingletonInstance
    {
        get
        {
            if (singletonInstance == null)
            {
                singletonInstance = new MyClass();
            }
            return singletonInstance;
        }
    }

    // the rest of your class implementation
}

Then, you can call your static method like so:

AnotherClass.UseMyClass(MyClass.SingletonInstance.Zero);


回答2:

Is your intent that the instance is provided by the caller of the delegate, and not the creator of the delegate? C# does support such an unbound delegate, it's called an open delegate, and the instance becomes a parameter.

You have to use Delegate.CreateDelegate to create an open delegate, something like this:

public class MyClass : IDisposable
{
  public delegate int DoSomething();

  public int Zero() {return 0;}
  public int One() {return 1;}

  public void Dispose()
  {
    // Cleanup
  }
}

public class AnotherCLass
{
    public static void UseMyClass(Converter<MyClass,int> func)
    {
      using (var mc = new MyClass())
      {
        // Call the delegate function
        func(mc);
      }
    }
}

AnotherClass.UseMyClass(
    (Converter<MyClass, int>)Delegate.CreateDelegate(
        typeof(Converter<MyClass, int>),
        typeof(MyClass).GetMethod("One")
    )
);

Of course, you can do it much more easily with a shim:

AnotherClass.UseMyClass( mc => mc.One() ); // C# 3 or later
AnotherClass.UseMyClass( delegate(MyClass mc) { return mc.One(); } ); // C# 2


回答3:

Cant be done without instantiation. Heres how you can do it:


public static void main(string[] args)
{
  // Call AnotherClass method, by passing Zero()
  // or One() but without instatiate MyCLass
  AnotherClass.UseMyClass((new MyClass()).Zero);
}