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

TypeBinder.Deserialize<T> should have new() constraint #40718

Open
Arithmomaniac opened this issue Dec 12, 2023 · 6 comments
Open

TypeBinder.Deserialize<T> should have new() constraint #40718

Arithmomaniac opened this issue Dec 12, 2023 · 6 comments
Labels
Azure.Core Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. feature-request This issue requires a new behavior in the product in order be resolved.
Milestone

Comments

@Arithmomaniac
Copy link
Contributor

public T Deserialize<T>(TExchange source)
{
if (_isPrimitive)
{
if (!_binderImplementation.TryGet(null, source, out T result))
{
throw new InvalidOperationException($"Unable to deserialize into a primitive type {typeof(T)}");
}
return result;
}
T o = Activator.CreateInstance<T>();

This method should have a new() constraint, as it can only handle primitive types or types with a parameterless constructor. Propagating the resulting new() constraints s up the call chain (such as to Azure.Monitor.Query.LogsQueryClient.QueryWorkspaceAsync<T>) would prevent runtime errors that could be caught at compile time instead.

@github-actions github-actions bot added customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Dec 12, 2023
@jsquire jsquire added Client This issue points to a problem in the data-plane of the library. Azure.Core feature-request This issue requires a new behavior in the product in order be resolved. and removed question The issue doesn't require a change to the product in order to be resolved. Most issues start as that needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. labels Dec 12, 2023
@jsquire jsquire self-assigned this Dec 12, 2023
@github-actions github-actions bot added the needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team label Dec 12, 2023
@jsquire jsquire added this to the Backlog milestone Dec 12, 2023
@jsquire
Copy link
Member

jsquire commented Dec 12, 2023

Thank you for your feedback. We'll add this to the Azure.Core backlog for consideration.

@jsquire jsquire removed the needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team label Dec 13, 2023
@jsquire
Copy link
Member

jsquire commented Jan 19, 2024

@AlexanderSher: Would you please take point for understanding the end-to-end scenario and making a recommendation on whether we should make this change?

@jsquire jsquire removed their assignment Jan 19, 2024
@AlexanderSher
Copy link
Contributor

Hi @Arithmomaniac

Adding new() constraint to the TypeBinder.Deserialize<T> would result in adding the same constraint to several public methods in the released libraries (e.g.: Azure.Data.Tables.TableClient.QueryAsync`), which would be a source breaking change for any code that has passes generic argument down the call stack.

@jsquire, @KrzysztofCwalina @tg-msft - do we allow this kind of source breaking change?

@jsquire
Copy link
Member

jsquire commented Jan 19, 2024

@jsquire, @KrzysztofCwalina @tg-msft - do we allow this kind of source breaking change?

Not outside of special circumstances such as security issues. If this feature would introduce breaking changes to the public API for stable packages, then this does not look like a change that we would make. Unless I'm overlooking something, the benefit of this change would be convenience (better runtime safety) - which would not outweigh the breaking change, in my opinion.

@Arithmomaniac
Copy link
Contributor Author

I figured this was probably the case. In which case, I would propose making an "audit" of upstream APIs and check which ones do and do not declare new() themselves. (I wouldn't mind putting this together). Then maybe do some combination of the following?

  1. Add documentation remarks (exception XML doc and general documentation) to all such members
  2. Have an internal Roslyn analyzer that checks whether this improper dependency is taken (errors could be suppressed for existing APIs, but new APIs wouldn't fall into this trap)
  3. Add the new() constraint whenever the API change is breaking (or when a new API supersedes the old one) anyways
  4. Adding fallback JSON-based deserialization for classes without parameterless constructors in the affected APIs. (For example, in LogsQueryResult, each row is a JSON array; in case of e.g. record Foo(int A, string B) and value [1, "2"], use JsonSerializer.Deserialize<Foo>("{\"A\": 1, \"B\": \"2\"}"))

@Arithmomaniac
Copy link
Contributor Author

Arithmomaniac commented Jan 28, 2024

I noticed that TypeBinder is an "opt-in compilation" file, and is only enabled in the following SDK projects:

  • Azure.Monitor.Query.csproj
  • Azure.Data.Tables.csproj
  • Microsoft.Azure.WebJobs.Extensions.Tables.csproj

And the Deserialize method only is used on the following paths:

  • Azure.Monitor.Query.RowBinder.BindResults
  • Microsoft.Azure.WebJobs.Extensions.Tables.TableEntityToPocoConverter.Convert
  • Azure.Data.Tables.DictionaryTableExtensions.ToTableEntity
    • Azure.Data.Tables.DictionaryTableExtensions.ToTableEntityList
      • Azure.Data.Tables.TableClient.Query(Async)
    • Azure.Data.Tables.TableClient.GetEntityInternalAsync
      • Azure.Data.Tables.TableClient.GetEntity(IfExists)(Async)

Given its small footprint, I think we should be able to at least do 1) and/or 4).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Azure.Core Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. feature-request This issue requires a new behavior in the product in order be resolved.
Projects
None yet
Development

No branches or pull requests

3 participants