dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.91k stars 4.01k forks source link

Feature request: Anonymous types that implement interfaces #13

Closed nvivo closed 8 years ago

nvivo commented 9 years ago

It would be very useful if C# anonymous types could implement interfaces, including methods. This would make a huge difference when developing using interface driven design. It would also allow for very easy mocking in unit tests.

interface IFooBar {
    string Foo { get; }
    int Bar(string s);
}

void MethodA () {
    // explicitly typed
    var myFooBar = new IFooBar {
        Foo = "xyz",
        Bar = s => s.Length
    };

    MethodB(myFooBar);
}

IFooBar MethodB(IFooBar fooBar) {
    // implicit typed
    return new {
        Foo = "abc",
        Bar = fooBar.Bar
    };
}

In TypeScript and other dynamic languages, this has proven to be really useful and reduces a lot of boilerplate code.

It seems that implementing this in C# wouldn't break any rules as anonymous types are already classes internally, and the compiler could just make it implement the interface and use the same rules for checking type.

The only issue I can think right now is the method implementation. How to differ between a method and a property that is a delegate:

interafce IFoo {
    int Bar(int i);
    Func<int, int> Baz { get; }
}

void IFoo GetFoo() {
    return new {
        Bar = i => 1, // ?
        Baz = i => 2; // ?
    }
}

It seems that from the perspective of the C# consumer it wouldn't make much difference, as both can be called using the same syntax (obj.Bar() or obj.Baz() ), but the compiler needs to know this.

This could be solved by either adding a new syntax to this implementation:

void IFoo GetFoo() {
    return new {
        Bar(int i) => 1,   // method
        Baz = i => 2;  // deletage
    }
}

Or by just defaulting to methods unless the interface calls for a property. That would make the first example with the same code valid, and I guess would make the syntax better.

nemec commented 9 years ago

I like the idea. Although anonymous types aren't meant to be passed outside the scope where they're created, interfaces are all about the contract so it doesn't matter much that the implementation is compiler-generated.

Per your suggestion about methods, it looks like C# 6 already blurs the line between methods and delegates (from a syntax standpoint), so maybe it's not such a far-fetched suggestion.

mattwar commented 9 years ago

The reason anonymous types are not passable outside the scope where they are created is due to a lack of unification of types across assemblies in the runtime, not a design philosophy. Giving anonymous types an interface is a good idea. I believe it was proposed during the design for anonymous types but was outside the intent of the feature at the time.

MadsTorgersen commented 9 years ago

This proposal seems related to object expressions in F# or anonymous inner classes in Java, both of which let you specify class implementations right when you new the objects up.

You could certainly imagine an evolution of anonymous objects in C# that would combine the current behavior with the ability to inherit classes, implement interfaces and supply member implementations.

nvivo commented 9 years ago

Thinking out loud here, it seems that I could break my proposal in two:

  1. Allow anonymous objects to include methods and writeable properties.
  2. Allow anonymous objects to implement interfaces

Once the first is achieved, the second one should be straightforward.

To me, it is clear the idea is very useful and would reduce drastically the number "dumb" classes I need just to return models in interface driven code.

But it raises some questions:

new {
    // new modifier keyword?
    readwrite Name = "foo",  
    readwrite string Name,

    // no types, always infer from the value?
    readwrite Name = default(string),

    // no value implies it will be set later, hence writeable? - looks strange
    string Name;

    // borrow syntax from real properties?
    string Name { get; set; },
    Name { get; set; } = "initial value",

    // or imply the get and require only the set?
    string Name { set; },
    Name { set; } = "initial value",
}
interface IPerson {
    string Name { get; set; }
    bool IsDeceased { get; set; }
}

IPerson GetPerson() {
    return new {
        Name = "John"
    };
}

This would create some form of "duck typing", making like implementing one-time used interfaces easier.

interface ISystemClock {
    DateTimeOffset Now()
} 

iocContainer.Resolve<ISystemClock>().With(new { Now() => DateTimeOffset.Now });
Porges commented 9 years ago

I duped this (as linked above), with an alternative syntax.

iSynaptic commented 9 years ago

+1

aluanhaddad commented 9 years ago

+1

dsaf commented 9 years ago

+1

@nvivo Are you requesting specifically interface implementations or subtyping as well?

Depending on that #1728 might be a duplicate.

Also what do you mean by saying "interface driven design"?

Relevant quote:

http://www.jot.fm/issues/issue_2005_07/article1.pdf

Note that as generalizations, interfaces compete with abstract classes. In fact, in practice interfaces and abstract classes are sometimes used as if they were the same concept. However, since abstract classes have the potential to pass on implementation to their subclasses, they should be used if (and only if) the relationship to the subclasses is genetic, i.e., if it is (or at least could be) based on the inheritance of internal structure, that is, implementation. If on the other hand the relationship is based on pure function (or, weaker still, on sameness of protocol), interfaces should be used. For instance, a linked list and a dynamic array would normally not be genetically related (i.e., have no common pieces of implementation), yet they share the interface of lists (specifying sequential access to their elements).

gafter commented 9 years ago

Note that records (#206) can implement interfaces. I think that satisfies the underlying need of this request.

dsaf commented 9 years ago

@gafter Can records be declared within method body? I think this request is about not polluting the namespaces and creating explicit named types, rather than creating immutable classes with compact syntax. I believe these are different.

jbtibor commented 9 years ago

+1

t00 commented 9 years ago

As anonymous classes are created with only getters available and only in the current scope this feature might be non-trivial to implement.

But implementation can happen in 2 stages, 1 for getter-only interfaces and 2 for getter and setter + methods.

I would say implementing only interfaces containing property getters would be a huge improvement and should not change anonymous constructor code apart from adding inheritance to the anonymous class.

Inheritance syntax should be explicit and any setter or method on the interface or missing property on the anonymous implementation should trigger an error:

interface IPerson
{
    string Name { get; }
    bool IsDeceased { get; }
}

interface IEmployee
{
    string Boss { get; }
}

IPerson GetPerson()
{
    return new : IPerson, IEmployee
    {
        Name = "John",
        IsDeceased = true,
        Boss = "OK",
        ExtraProperty = 123
    };
}
aluanhaddad commented 9 years ago

I am skeptical of the property implementation syntax, I think it should be something like

return new : IPerson, IEmployee
{
    Name => "John",
    IsDeceased => true,
    Boss => "OK",
    ExtraProperty => 123
};

or

return new : IPerson, IEmployee
{
    Name { get; } = "John",
    IsDeceased { get; } = true,
    Boss { get; } = "OK",
    ExtraProperty { get; } = 123
};

because we are defining a type that implements the properties of the interfaces, where as in the case of anonymous types, the compiler is generating a type definition for us based on the names and values of the instantiation expression.

jcdickinson commented 8 years ago

+1

Also thinking out loud here.

Concern 1

What about methods? One thing I've done for mock objects (without a mocking framework) in the past is to store a delegate that has the matching signature in a private field and invoke that from the interface. E.g.

interface ICustomer {
  string Name { get; }
  string Surname { get; }
  bool IsValid();
}

return new ICustomer() {
  Name = "Jim",
  Surname = "Bob",
  IsValid = () => true
};

This would roughly compile to:

class ICustomerAnyonymousType {
  public string Name { get; set; }
  public string Surname { get; set; }
  public Func<bool> IsValidImplementation { get; set; } // Or a private field
  public bool IsValid() {
    var impl = IsValidImplementation;
    if (impl == null) throw new NotImplementedException(); 
    return impl(); 
  }
}

return new ICustomerAnyonymousType() {
  Name = "Jim",
  Surname = "Bob",
  IsValidImplementation = () => true
};

Concern 2

What about default values? I might not want to provide an implementation for a method or omit a property. Possibly:

return new default ICustomer() {
  Name = "Jim"
};

Surname would return null, and IsValidImplementation would be set to null (causing a NotImplementedException). If default is omitted all members must be provided (else there will be compile failure).

Why?

Unit tests and mocking. For trivial scenarios (not involving abstract or sealed classes) you could mock your objects as follows:

[Fact]
public void DisplayCustomer_ValidateCalled()
{
    var validateCalled = false;
    var customer = new ICustomer() {
      Name = "Jim",
      Surname = "Bob",
      IsValid = () => validateCalled = true
    }
    sut.Display(customer);
    Assert.True(validateCalled);
}

[Fact]
public void DeleteCustomer_Deleted()
{
    var customer = new default ICustomer() {
      Name = "Jim",
      Surname = "Bob"
      // Omit IsValid because it is never called.
      // NotImplementedException would be thrown if it was
      // somehow called.
    }
    sut.Deleted(customer);
    Assert.Null(sut.GetCustomer(customer));
}
alrz commented 8 years ago

@jcdickinson

return new ICustomer() {
  Name = "Jim",
  Surname = "Bob",
  IsValid = () => true
};

It's not clear that you're initializing a property of type Func<bool> or implementing the method. I think this should be done in a more explicit way like:

return new ICustomer {
  public string Name => "Jim";
  public string Surname => "Bob";
  public bool IsValid() => true;
};
jcdickinson commented 8 years ago

@alrz +1. Just use a comma for consistency. Isn't the return type+visibility redundant (unless internal interfaces make an appearance)?

return new ICustomer {
  Name = "Jim",
  Surname = "Bob",
  IsValid() => true,
  Foo = bar,
  Baz() => false
};
alrz commented 8 years ago

This looks more like a initialization block rather than class declaration. Also it could be implemented as a nested local type (#259) so naturally you would expect anonymous classes as well:

return new BaseClass() {
    public override bool IsValid() => true;
    ...
};

PS: comma was a typo, sorry.

jcdickinson commented 8 years ago

Within context of this issue/feature it's about anonymous types and we should likely extend syntax instead of breaking existing syntax.

nvivo commented 8 years ago

@arlz, these two look exactly the same to me:

IsValid() => true
public override bool IsValid() => true

adding modifiers doesn't change that, only makes more verbose.

jcdickinson commented 8 years ago

@nvivo I think @alrz is bringing in inspiration across from #259, which could succeed/replace this feature - but that has already been specced over on that issue. I prefer the more succinct syntax, like you, as anything more is entirely redundant and doesn't look like the current anonymous types at all.

alrz commented 8 years ago

I'm talking about a more general feature like "implementing interfaces anonymously" instead of "anonymous types implementing interfaces". I borrowed all this from Java, though.

gafter commented 8 years ago

It anonymity really important? Compared to local (within a block) class declaration as an alternative way of handling this. It is nice that this lets you stay in an expression context, it is true, but I do not think the use cases are really simplified much.

jcdickinson commented 8 years ago

It anonymity really important?

For Linq I'd assume it would be crucial.

public IEnumerable<ICustomer> GetCustomers() {
  return from c in db.Customers
        select new {
          Name = c.Name,
          Surname = c.Surname
        };
}

In addition:

Does inventing new syntax here for anonymous-but-no-so-anonymous-types add anything at all? Even just one thing? Versus adding either nothing (if method declarations are not supported) or re-using the lambda grammar (if method declarations are supported); both also have significantly less keystrokes, significantly less indentation and are far easier to human-parse. Less syntax makes a language good, not more. Once you have added syntax you can never remove it, in opposition: using existing syntax should be largely familiar to experienced developers.

gafter commented 8 years ago

We have no expectation of ever doing anything like this.

Porges commented 8 years ago

That's disappointing.

Here's an example that came up today. Let's say we have some interface IParseMessages:

interface IParseMessages
{
    bool Parse(IMessage message);
}

Now we want to be able to add other stages to the parsing pipeline (think something like the handlers in ASP.NET), which can decide whether or not to invoke the "base" message parser. None of these handlers know anything about each other (we can't just link them all together when we write them). We could have a type like this:

public interface IMessageHandler
{
    bool Parse(IMessage message, Func<IMessage, bool> inner);
}

The IMessageHandler can now check the message and then decide whether or not to call onto the inner handler.

Something that would be useful here would be to be able to fuse two message handlers together to form a new handler:

public static class MessageHandlerExtensions
{
    public static IMessageHandler Then(this IMessageHandler derived, IMessageHandler baseImpl)
        => new ComposedMessageHandler(derived, baseImpl);

    private sealed class ComposedMessageHandler : IMessageHandler
    {
        private readonly IMessageHandler _derived;
        private readonly IMessageHandler _baseImpl;

        public ComposedMessageHandler(IMessageHandler derived, IMessageHandler baseImpl)
        {
            _derived = derived;
            _baseImpl = baseImpl;
        }

        public bool Parse(IMessage message, Func<IMessage, bool> inner)
            => _derived.Parse(message, msg => _baseImpl.Parse(msg, inner));
    }
}

Now, if we have a list of IMessageHandlers we can combine them all with something like (depending on what order you want them applied) handlers.Aggregate((d, b) => b.Then(d)). (AKA, IMessageHandlers are monoidal).

You might notice that that's a lot of typing. It would be nice to be able to write this instead, replacing all the code in the last block (using my proposed syntax):

public static class MessageHandlerExtensions
{
    public static IMessageHandler Then(this IMessageHandler derived, IMessageHandler baseImpl)
        => new IMessageHandler with {
           bool Parse(IMessage message, Func<IMessage, bool> inner)
               => derived.Parse(message, msg => baseImpl.Parse(msg, inner));
        };
}

Aside: compare the F# which would be something like:

let combine (derived : IMessageHandler) (baseImpl : IMessageHandler) =
    { new IMessageHandler with
        member __.Parse msg inner =
            derived.Parse msg (fun m -> baseImpl.Parse m inner) }

Finally, we then need a way to augment an IParseMessages with the combined IMessageHandler, to produce a new fused IParseMessages that we can pass around. In current C# this could be something like:

public static class MessageParserExtensions
{
    public static IParseMessages Augment(this IParseMessages me, IMessageHandler handler)
        => new AugmentedMessageParser(handler, me);
}

sealed class AugmentedMessageParser : IParseMessages
{
    private readonly IMessageHandler _handler;
    private readonly IParseMessages _impl;

    public AugmentedMessageParser(IMessageHandler handler, IParseMessages impl)
    {
        _handler = handler;
        _impl = impl;
    }

    public bool Parse(IMessage message) => _handler.Parse(message, _impl.Parse);
}

Using the proposed syntax this could be reduced to the much smaller:

public static class MessageParserExtensions
{
    public static IParseMessages Augment(this IParseMessages me, IMessageHandler handler)
        => new IParseMessages with { 
            bool Parse(IMessage message) => handler.Parse(message, me.Parse); };
}

Again, to compare with F# this would be:

let augment (me : IParseMessages) (handler : IMessageHandler) =
    { new IParseMessages with
        member __.Parse msg = handler.Parse msg me.Parse}

I think this reduction in boilerplate would be very useful.

svick commented 8 years ago

@Porges A lot of that boilerplate could be also removed by using a record (part of #206).

aluanhaddad commented 8 years ago

It anonymity really important? Compared to local (within a block) class declaration as an alternative way of handling this. It is nice that this lets you stay in an expression context, it is true, but I do not think the use cases are really simplified much.

@gafter Are local type declarations still on the table? To me this is all about scoping.

aluanhaddad commented 8 years ago

In addition to scoping, I think capturing generic parameters could make this quite useful.

alrz commented 8 years ago

@aluanhaddad #9523

aluanhaddad commented 8 years ago

@alrz Thanks!

Richiban commented 8 years ago

I've literally wanted this feature for years... If it worked then say goodbye to fakes, mocks and generated decorators!

This might give new lease of life to anonymous types since, as far as I can tell, they're about to be completely superseded by tuples. Giving them the ability to implement interfaces would give them a reason to continue existing.

arfilon commented 7 years ago

I does not have to be perfect , it is anonymous types after all , i think implementing the interface geter without extra syntax like in the (t00 commented on Jul 24, 2015) cover 90% of the day to day need.

the idea is not to have full functional class, to do that just use a private class, we need to have ability to pass data when interface required, just like what we do in anonymous type in linq ,if the code try to consume the set method ,show an error or throw an Exception at run time, just like anonymous types.

tuple that can't implementing interface, will not solve the problem.

nvivo commented 7 years ago

I still think this is a very required feature, but this issue has been closed and I don't believe the team will respond this issue again.

Someone with time to discuss should open a new issue proposing a simpler version of this and see what can get out of it.

Spacefish commented 7 years ago

This would be great to implement multiple action callbacks.. Image a class which downloads a file: Callback Interface:

public interface IDownloadResultHandler {
    void Success(string path);
    void Fail();
}

Class:

public class FileDownloader {
  public static void Download(string path, IDownloadResultHandler callback) {
    // starts download on a second thread and returns but keeps handle to callback
    ....
  }
  internal static void downloadThread() {
   ...
   if(success) {
     this.callback.Success(pathOfFile);
   }
   else {
      this.callback.Fail();
    }
  }
}

Later on this could be used like this

MyConsole console = new MyConsole();
FileDownloader.Download("/path/to/file", new : IDownloadResultHandler {
    Success() { console.Write("Success"); }
    Fail() { console.Write("Failed.."); }
});

Currently one has to implement a seperate class which implements the interface and pass the environment via a constructor parameter or inject it via dependency injection..

Having anonymous Implementations of interfaces could save us from a lot of boilerplate code.. Furthermore "Callbacks" could explicitly state if they support a different functionality by implementing a interface or not!

Porges commented 7 years ago

I'm going to post another example just 'cause.

Here's some C#:

public Sink<TIn, TResult2> MapResult<TResult2>(Func<TResult, TResult2> projection)
    => new MappedResult<TResult2>(this, projection);

private sealed class MappedResult<TResult2> : Sink<TIn, TResult2>
{
    private Sink<TIn, TResult> _sink;
    private Func<TResult, TResult2> _projection;

    public MappedResult(Sink<TIn, TResult> sink, Func<TResult, TResult2> projection)
    {
        _sink = sink;
        _projection = projection;
    }

    public override ActiveSink<TIn, TResult2> Open() => new Impl(_sink, _projection);

    private sealed class Impl : ActiveSink<TIn, TResult2>
    {
        private ActiveSink<TIn, TResult> _sink;
        private Func<TResult, TResult2> _projection;

        public Impl(Sink<TIn, TResult> sink, Func<TResult, TResult2> projection)
        {
            _sink = sink.Open();
            _projection = projection;
        }

        public override TResult2 Result => _projection(_sink.Result);

        public override void Dispose() => _sink.Dispose();

        public override Task ProcessChunk(ReadOnlySpan<TIn> span, CancellationToken cancellationToken)
            => _sink.ProcessChunk(span, cancellationToken);
    }
}

Here's the exact same thing using object expressions in F#:

member me.MapResult (projection : 'TResult -> 'TResult2) : Sink<'T, 'TResult2> =
    { new Sink<'T, 'TResult2>() with
      override __.Open() = 
        let activeSink = me.Open() in
        { new ActiveSink<'T, 'TResult2> with
          override __.Dispose() = activeSink.Dispose()
          override __.ProcessChunk c ct = activeSink.ProcessChunk c ct
          override __.Result with get() = projection activeSink.Result
        }
    }

Being able to close over variables in anonymous type definitions cuts down on a lot of boilerplate.

By comparison, here is the equivalent Java (with anonymous classes):

  public <TResult2> Sink<TIn, TResult2> MapResult(Function<TResult, TResult2> f)
  {
    Sink<TIn, TResult> me = this;
    return new Sink<TIn, TResult2>() {
      public ActiveSink<TIn, TResult2> open() {
        ActiveSink<TIn, TResult> activeSink = me.open();
        return new ActiveSink<TIn, TResult2>() {
          public TResult2 result() { return f.apply(activeSink.result()); }
          public void close() { activeSink.close(); }
          public void processChunk(TIn[] c) { activeSink.processChunk(c); }
        };
      }
    };
  }

And here's a hypothetical "C# with anonymous classes/object expressions":

public Sink<TIn, TResult2> MapResult<TResult2>(Func<TResult, TResult2> f)
{
    var me = this;
    return new Sink<TIn, TResult2> with {
        override ActiveSink<TIn, TResult2> Open() {
            var activeSink = me.Open();
            return new ActiveSink<TIn, TResult2> with {
                override TResult2 Result => f(activeSink.Result);
                override void Dispose() => activeSink.Dispose();
                override Task ProcessChunk(TIn[] c, CancellationToken ct)
                    => activeSink.ProcessChunk(c, ct);
            };
        }
    };
}
ghost commented 7 years ago

I've been working with Xamarin for Android recently, and because the underlying API is Java based, you're generally expected to pass in an interface implementation where typical C# conventions would use delegates or lambdas. In Java this is simple: use an anonymous class. In C#, you end up creating multiple unnecessary classes and it's very cumbersome.

crystalcodesoftware commented 6 years ago

We have no expectation of ever doing anything like this.

Well, boo to you.

gafter commented 6 years ago

Local type declarations are still on the table.

The most value I ever got from anonymous types in Java was a series of counterintuitive examples for the book Java Puzzlers.

jnm2 commented 6 years ago

I have never written Java, so am I missing something? I still really want this for C#.

gafter commented 6 years ago

I don’t know what you may be missing, but I believe that local class declarations give you the full power in a much more readable and clear form.

jnm2 commented 6 years ago

I'm willing to give that a try first.

jbtibor commented 6 years ago

@gafter Are there local classes in C#? Or this is a future feature? I agree that local classes would make anonymous interface implementations redundant.

jnm2 commented 6 years ago

@jbtibor https://github.com/dotnet/csharplang/issues/130

Spacefish commented 6 years ago

@jnm2 that´s not really the same thing.. anonymous types implementing an interface would allow you to pass them as a reference to multiple callbacks to a long running action / task.. Such a pattern is heavily used in Android in Java.. There are typically multiple things that could happen if you trigger some asynchronous actions.. If you only have one callback/delegate you have to have multiple parameters which are not used in all cases, passing an object which implements functions for that cases looks much cleaner / is more readable.

jnm2 commented 6 years ago

@Spacefish And well I know it. I was answering @jbtibor's question, "Are there local classes in C#? Or this is a future feature?"

HaloFour commented 6 years ago

@gafter

I don’t know what you may be missing, but I believe that local class declarations give you the full power in a much more readable and clear form.

But with unnecessary boilerplate, even by Java standards. In my experience local type declarations are nearly non-existent in the Java ecosystem, but anonymous classes are exceptionally common. This was especially true leading up to Java finally getting lambdas. If you look at any of the helper packages for Java that deal in functional concepts or callbacks they all use anonymous types, including those from Google, Netflix, Apache, Amazon, etc., both internally and in any example they provide for using their APIs.

I could probably count the number of times I've seen local declarations in the wild on one hand, at best. The only times I've ever reached for them myself was to emulate closures in lambdas due to Java forcing all enclosed locals to be effectively final. With Java 10 that's no longer necessary and I will refactor all of that code to using anonymous classes instead.

public IDisposable Foo() {
    class Foo : IDisposable {
        public void Dispose() {
            Console.WriteLine("Disposed!");
        }
    };
    return new Foo();
}

vs.

public IDisposable Foo() => new IDisposable {
    void Dispose() => Console.WriteLine("Disposed!");
};

There's nothing unreadable about that second example. If anything I think it does a much better job of focusing on what it actually does.

HaloFour commented 6 years ago

@gafter

Furthermore, if Java/Android interop is given as one of the reasons for adopting default interface members (of which I am in favor, regardless of the justification), then I can state that the same interop is a good reason to adopt anonymous classes.

As @errorx666 stated, Android dev is interface-driven for callbacks. This makes them cumbersome to use from C# as you have to declare an entire separate class. Local types help, but that's still a lot of ceremony to declare and instantiate to effectively emulate what would be an exceptionally verbose lambda. To improve that situation from C# I would recommend that anonymous types are considered. Even better would be to allow lambda syntax with interfaces with exactly one required method (or also expand that out to abstract types, like Scala supports). Incidentally, poking at the Android docs, they clearly favor anonymous classes also.

gafter commented 6 years ago

that the same interop is a good reason to adopt anonymous classes.

Are there public APIs in Java that have anonymous types?

HaloFour commented 6 years ago

@gafter

Are there public APIs in Java that have anonymous types?

No, there are public APIs throughout Java and the Java ecosystem that expose interfaces for use as callbacks, and the idiomatic (and natural) approach to implementing them is via anonymous types.

https://github.com/google/guava/wiki/FunctionalExplained https://hc.apache.org/httpcomponents-asyncclient-ga/quickstart.html https://commons.apache.org/proper/commons-functor/examples.html https://github.com/Netflix/Hystrix/wiki/How-To-Use#Reactive-Execution http://reactivex.io/documentation/operators/filter.html https://developer.android.com/guide/topics/ui/ui-events https://developer.android.com/guide/topics/location/strategies https://docs.oracle.com/javafx/2/events/handlers.htm https://docs.oracle.com/javase/7/docs/api/java/beans/EventHandler.html http://netty.io/wiki/user-guide-for-4.x.html#wiki-h3-9 https://jersey.github.io/documentation/latest/rx-client.html https://github.com/AsyncHttpClient/async-http-client#using-custom-asynchandlers

I honestly think you'd find it pretty difficult to find API docs that would suggest implementing callback interfaces using local types over anonymous types.

svick commented 5 years ago

@RUSshy See the comment above: https://github.com/dotnet/roslyn/issues/13#issuecomment-173413281

We have no expectation of ever doing anything like this.

Also, this kind of issue now belongs to the csharplang repo, and there is a very similar request already opened there: https://github.com/dotnet/csharplang/issues/1542.