c# Is it possible to supply a lambda when an interface is required?

12,679

Solution 1

Delegates cannot implement interfaces (directly).

Two good options come to mind:

  1. Change the definition of the method that you're calling to take a delegate types instead of an IProgress type. (If possible; this would be the preferable option)

  2. Create a new type that implements the interface that you need and takes a delegate as a parameter to implement that functionality.

And example of #2, while dependent on the interface, might look something like this:

interface IProgress<T>
{
    void doStuff(T param);
}

class LambdaProgress<T> : IProgress<T>
{
    Action<T> action;
    public LambdaProgress(Action<T> action)
    {
        this.action = action;
    }

    public void doStuff(T param)
    {
        action(param);
    }
}

then you'd be able to do something like:

B(new LambdaProgress<Object>(obj => ...));

Solution 2

No, you can't supply a lambda when an interface is required.
But you can supply an anonymous object by using impromptu-interface.

This example is from its project page:

//Anonymous Class
var anon = new
{
    Prop1 = "Test",
    Prop2 = 42L,
    Prop3 = Guid.NewGuid(),
    Meth1 = Return<bool>.Arguments<int>(it => it > 5)
}

var myInterface = anon.ActLike<IMyInterface>();

In your example this can be:

A
{
    // Create an anonymous object.
    var anonymous = new
    {
        // Define a method that needs an "object" parameter and returns nothing.
        Report = Return.Arguments<object>(m =>
        {
            // Do whatever you want to do when Report is called.
        })
    }

    // Get your anonymous object as an IProgress<Object>.
    var obj = anonymous.ActLike<IProgress<Object>>

    // Call B.
    B(obj);
}

Solution 3

Assuming that your IProgress<object> interface has just the single void Report(object) method, and that you control the API, you could simply redefine the methods that currently require a parameter of type IProgress<object> to instead require a new delegate type:

public delegate void ProgressReportDelegate(object someObject);

Then your example could change to:

method in class A {
...
Action<Object> Report = (m) => { // do something useful with m };

B(Report)
}

method B(ProgressReportDelegate reporter) {
   reporter(someObject);
}

For more complex interfaces, or where you don't control the API (and so can't change a method to take the delegate rather than on object implementing that interface), this isn't really an option, but it would appear to work in your case.

Share:
12,679

Related videos on Youtube

Michael Ray Lovett
Author by

Michael Ray Lovett

Updated on September 15, 2022

Comments

  • Michael Ray Lovett
    Michael Ray Lovett over 1 year

    In some class method, A, I need to call a library method B, which takes as an IProgress<Object> as a parameter.

    Normally, I might either implement IProgress<Object> as part of class where A resides, and then pass "this" to method B. Or perhaps I might create a new class whose only purpose is to implement IProgress<Object> and handle it correctly-- then in this case I'd create an instance of that class and pass it to B.

    But what I really want is to have my implementation of IProgress<Object> to appear right inside the method in which I'm calling B, so that there's less of a visual disconnect between the calling code, and the IProgress<Object> implementation. (I consider my implementation of IProgress to be kind of a private, non-shared detail of the calling method and thus I don't want my implementation of IProgress<Object> to be in a whole separate method of perhaps a whole other class).

    What I've been trying to do is use a lambda in which I will define my short progress handling, and then somehow pass this lambda to B, like this:

    method in class A {
    ...
    Action<Object> Report = (m) => { // do something useful with m };
    
    B(Report)
    }
    
    method B(IProgress<Object> reporter) {
       reporter.Report(some object)
    }
    

    Of course, I know why this won't work as is - B is wanting an object that implements IProgress<Object> and I'm handing it an Action object instead.

    Is there any way to achieve what I'm trying to achieve? (IE have my implementation if IProgress<Object> appear inside method A?

    • Hristo Iliev
      Hristo Iliev over 11 years
      C# lambdas are anonymous delegates. What you need is an anonymous type which implements the interface. See this question for some workarounds over the only-public-properties anonymous types that C# provides.
  • wensveen
    wensveen over 2 years
    This answer is correct when the question is actually about System.IProgress<T> which isn't explicitly stated, but it is implied.
  • Servy
    Servy over 2 years
    This question isn't asking about the .NET IProgress<T> interface. It was asked before that interface event existed. They're asking about their own custom interface.
  • A.T.
    A.T. over 2 years
    The solution here is to use the new IProgress in combination with the new Progress class rather than rolling your own.
  • Servy
    Servy over 2 years
    The problem is how to implement an arbitrary interface using a delegate. That the one example used to demonstrate the problem happened to be called IProgress is irrelevant to the question. The question did not ask how to update the UI of a desktop application from a background process with the progress of that background task. You're answering a different question than the one that was asked. Given that their question mentions nothing about marshaling to a UI thread, it's not even clear that your solution is even applicable to the context in which they're reporting progress.