Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DispatchProxy needs a non-generic Create API #28419

Closed
AmirShokr opened this issue Jan 14, 2019 · 5 comments
Closed

DispatchProxy needs a non-generic Create API #28419

AmirShokr opened this issue Jan 14, 2019 · 5 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Reflection
Milestone

Comments

@AmirShokr
Copy link

Currently DispatchProxy just provides the following Generic API to create a proxy :
public static T Create<T, TProxy>() {..}

However, when you want to create Proxies dynamically (on the fly) , you need a non-generic method like this:
public static object Create(Type contract, Type DispatchProxy)

the proposed implementation would be very simple like:

public static object Create(Type contract, Type DispatchProxy)
{
return DispatchProxyGenerator.CreateProxyInstance(DispatchProxy, contract);
}

@MichalStrehovsky
Copy link
Member

The existing generic API is generic to make it friendly to ahead of time compilation. Adding non-generic overloads will make this API difficult to support ahead of time in a reliable manner.

AOT compiled .NET doesn't use the implementation in this repo that you're referring to in your proposed implementation (since that one relies on Reflection.Emit) - the implementation is generated on the fly by the compiler by analyzing the T's that the method is called with. It's much more difficult to analyze System.Type instances.

@AmirShokr
Copy link
Author

AmirShokr commented Jan 14, 2019

I know what is AOT compilation and how it works. But I do not understand what you mean by "to support ahead of time in a reliable manner".

I think you are mixing 2 different API requirements here:

1)Generic APIs : for friendly AOT compilation (at design time)
2)Non-generic API: for advanced dynamic/on-the-fly requirements (at runtime)

A developer who is using a non-generic API, knows that what he/she is dealing with and you guys as the developers of this module should not and would not need to support anything for that API.

With not adding this API, you are stopping developers from dynamically creating proxies on the fly for dynamically discovered services.

ProtoBuf-net developer(s) had the same dilemma: https://github.com/mgravell/protobuf-net

if you look at their development history. They first introduced a generic API for de-serialization.

T Deserialize(Stream source)

Then with community feedback/request, they introduced a separate non-generic API:

NonGeneric.Deserialize(Type type, Stream source)

And at the end, they merged that non-generic API to the main API and now it is like :

public static class Serializer
{
...
T Deserialize(Stream source)
Deserialize(Type type, Stream source)
....
}

@MichalStrehovsky
Copy link
Member

A developer who is using a non-generic API, knows that what he/she is dealing with and you guys as the developers of this module should not and would not need to support anything for that API.

That's the crux of the problem. It's non-obvious that DispatchProxy.Create<Foo, IBar>(); is guaranteed to work and DispatchProxy.Create(typeof(Foo), typeof(IBar)) will only work sometimes. Nobody reads the documentation.

The serialization example you're referring to is a good one. I've worked on the AOT compiler for .NET Core for 6 years now and debugged plenty of real world applications that had trouble with serialization. Developer of the app choosing to use APIs that use System.Type instead of the generic overloads in situations where it would be totally possible to just structure the code to use the generic overloads that are guaranteed to work was a very common pattern.

If you really need the version that takes System.Type, you can just make one with MakeGenericMethod (and it will have the exact set of problems I described above). But I would prefer the non-generic overloads to be very undiscoverable and non-obvious.

@AmirShokr
Copy link
Author

AmirShokr commented Jan 15, 2019

I am already using MakeGenericMethod and have my own error handling around my 'Create' method. And I do believe that it is very obvious that Create(type, type) may fail in runtime and the developer should have error handling around it.
I was hoping I can avoid reflection here, but it seems you guys are highly opinionated about this API.

However, you need to keep in mind that in any progressive and extensible SOA architecture which dependencies/services are injected/discovered in runtime, there is an absolute need to have proxies/serializers which support non-generic APIs because you just simply do not know the concrete types in design time.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 5.0 milestone Feb 1, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@GrabYourPitchforks
Copy link
Member

As mentioned at #28419 (comment), the generic-only implementation is beneficial to our core scenarios. The workaround of using MakeGenericMethod has already been talked about here, and it should solve the problem satisfactorily. A custom wrapper or extension method could also assist with this inside your application.

@GrabYourPitchforks GrabYourPitchforks removed the untriaged New issue has not been triaged by the area owner label Mar 4, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Reflection
Projects
None yet
Development

No branches or pull requests

5 participants