1

In Java, I'm able to do the following:

Java

public class Button {
    private Callback callback;

    public Button(Callback callback) {
        this.callback = callback;
    }

    public void update() {
        // Check if clicked..
        callback.onClick(this);
    }

    public interface Callback {
        public void onClick(Button Button);
    }
}

And use it like:

Button b = new Button(new Callback() {
    @Override
    public void onClick(Button b) {
        System.out.println("Clicked");
    }
});

And I'm wondering, if the same is possible in (Unity) C#.

Currently I have the same setup, with the correct syntax

C#:

public class Button {
    private Callback callback;

    public Button(Callback callback) {
        this.callback = callback;
    }

    public void Update() {
        // Check if clicked..
        callback.OnClick(this);
    }

    public interface Callback {
        void OnClick(Button button);
    }
}

However, when I try to do the same when creating a button,

Button b = new Button(new Button.Callback() {
    void OnClick(Button button) {
        Debug.Log("Clicked");
    }
});

I get errors like:

Unexpected symbol 'void'

error CS1526: A new expression requires () or [] after type

error CS8025: Parsing error

I've tried making the method 'virtual' or 'abstract' in the interface, or adding the 'new' keyword before void OnClick(.. when I create the button, but no luck so far.

It seems that the unexpected symbol 'void' error dissapears if I remove the '()' from 'new Button.Callback'

I would appreciate some help here.


  • C# has events - L.B
  • I'm having more luck finding answers now, I didn't know it was called an inline interface. Thanks for the links too. - Snakybo
  • The unity tag is for Microsoft Unity. Please don't misuse it. - Lex Li

3 답변


2

What you are trying to do (i.e. anonymous interfaces) is not possible in C#. However, you could use delegates to achieve something similar,

public class Button {
    private Action<Button> action;

    public Button(Action<Button> action) {
        this.action = action;
    }

    public void Update() {
        // Check if clicked..
        action(this);
    }
}

Then,

Button b = new Button(delegate(Button button) { Debug.Log("Clicked"); });

Or using a lambda expression, which makes it look simpler,

Button b = new Button(button => Debug.Log("Clicked"));

Action is basically a generic type that represents a function, specifically a function with return type of void. Thus you can pass in existing methods as long as they comply with the signature void Method(). If you specify any type parameters (using the Action<T> syntax) you are specifying the number and types of arguments the represented function accepts, thus Action<Button> is a function that returns void and takes in a single argument of type Button, just like your Callback.OnClick method.

Instead of using an anonymous delegate or a lambda expression (e.g. like above), you can pass in a method that complies with the expected signature,

void OnClick(Button button)
{
     Debug.Log("Clicked");
}

and pass it,

 Button b = new Button(OnClick);


  • Is Action a build in class or a custom made class that handles the button clicks? - Snakybo
  • Yes, it is basically a generic type that represents a function, specifically a function with return type of void. Thus you can pass in existing methods as long as they comply with the signature void Method(Button button) - rae1
  • I got it working, thank you very much! - Snakybo
  • No problem; glad to help. =) - rae1

2

You are looking for Event handlers:

Maybe you want something like this:

public delegate void Callback(Button btn);
public class Button
{

    public event Callback Click;
    public Button(Callback callback)
    {
        Click += callback;
    }

    public void Update()
    {
        // Check if clicked..
        if (Click != null)
        {
            Click(this);
        }
    }


}

Usage:

Button btn = new Button( b => Debug.Log("Clicked"));


2

I think all you need is to implement your interface in final class like this:

public class SomeClass: Callback
{
    public SomeClass()
    {
       Button b = new Button(this);
    }


    void OnClick(Button button)
    {
        Debug.Log("Clicked");
    }

}

Linked


Related

Latest