Runtime: Deve haver uma versão .Net Standard 2.0 do Reflection.Emit?

Criado em 27 abr. 2018  ·  58Comentários  ·  Fonte: dotnet/runtime

System.Reflection.Emit não faz parte do .Net Standard, mas existem pacotes que permitem usá-lo de uma biblioteca .Net Standard (especificamente, System.Reflection.Emit e System.Reflection.Emit.Lightweight ). Mas esses pacotes não possuem uma versão .Net Standard 2.0, apenas versões .Net Standard 1.x.

Isso tem algumas implicações:

  • Bibliotecas .Net Standard 2.0 não podem usar typeBuilder.CreateType() (embora este código funcione tanto em .Net Framework 4.6.1 quanto em .Net Core 2.0) e devem usar typeBuilder.CreateTypeInfo().AsType() lugar. É possível que também existam outras APIs como esta.
  • Bibliotecas .Net Standard 2.0 que desejam usar Reflection.Emit ainda precisam usar pacotes .Net Standard 1.x-style System. *.

Esses problemas seriam resolvidos se uma versão .Net Standard 2.0 fosse adicionada aos pacotes Reflection.Emit. Isso é algo que valeria a pena fazer?

Embora ambos sejam problemas bastante pequenos, não tenho certeza de quanto valor acrescentaria isso.

area-System.Reflection.Emit question

Comentários muito úteis

Obrigado a todos pelo feedback. Com base no feedback esmagador, relistamos a versão mais recente dos pacotes existentes:

https://www.nuget.org/packages/System.Reflection.Emit/4.3.0
https://www.nuget.org/packages/System.Reflection.Emit.Lightweight/4.3.0

No entanto, conforme mencionado anteriormente neste tópico, esses pacotes afirmam ser compatíveis com o netstandard1.1, mas isso é uma mentira. Eles funcionarão apenas no .NET Core e .NET Framework. Portanto, se você os estiver consumindo de uma biblioteca netstandard, espere que essa biblioteca falhe se for executada em qualquer outra implementação .NET Standard.

Ainda não temos uma ótima solução para suportá-los no netstandard2.0, mas os proprietários ( @AtsushiKan @joshfree) do System.Relfection.Emit tentarão descobrir a solução de longo prazo.

Todos 58 comentários

@ericstj @weshaggard você sabe se é propositalmente dessa forma ou um descuido?

Foi intencional. Para bibliotecas como essa, que têm suporte irregular e nenhuma implementação portátil, paramos de enviar pacotes. A expectativa é que você tenha como alvo uma estrutura específica, se necessário. Para alguns, trouxemos pacotes com minas terrestres (implementações de lançamento em algumas plataformas). As pessoas poderiam propor que o adicionássemos de volta, mas este em particular teve um grande debate no passado devido à falta de suporte em todos os frameworks .net baseados em AOT. / cc @terrajobst

@ericstj

A expectativa é que você tenha como alvo uma estrutura específica, se necessário.

Como vou aprender sobre isso? Pelo que eu posso dizer, Reflection.Emit não é relatado pelo compatível com a plataforma. E quando eu google "reflexão emit. Padrão líquido", o único resultado na primeira página que diz se você deve usá-lo dessa forma é um tweet de julho de 2017 de @terrajobst sugerindo que você deve fazê-lo (talvez a situação tenha mudado desde então ?).

Vou deixar @terrajobst responder a isso, talvez ele estivesse pensando sobre o recurso gaurdrails nuget que tínhamos nos pacotes 1.xe 1.x. Com eles, tínhamos implementações irregulares e suporte de tempo de construção para mensagens de que coisas não são suportadas. Não estou particularmente inclinado para um lado ou para o outro aqui, apenas explicando como as coisas estão funcionando no momento. Acho que se conseguirmos a aprovação das pessoas sobre a adição de um pacote com uma implementação de plataforma não suportada, poderemos fazê-lo.

FWIW tudo o que está disponível em uma estrutura, mas não está no padrão da rede ou em uma biblioteca / pacote com um ativo padrão da rede significa que você precisa direcionar a estrutura para obtê-lo. Isso é tudo que eu quis dizer com meu comentário de expectativa.

@ericstj

tudo o que está disponível em uma estrutura, mas não está no padrão da rede ou em uma biblioteca / pacote com um ativo padrão da rede significa que você precisa direcionar a estrutura para obtê-lo. Isso é tudo que eu quis dizer com meu comentário de expectativa.

Mas aqui o pacote (com ativos .Net Standard 1.x) existe. Não acho que você possa simplesmente parar de atualizar um pacote e presumir que as pessoas não o usarão mais. No mínimo, você deve ter uma documentação explicando a situação.

O maior problema com System.Reflection.Emit é que não temos uma maneira de fornecer a biblioteca de uma forma padrão de rede por causa do TypeInfo (consulte https://github.com/dotnet/corefx/issues/14334). O pacote existente visa netstandard1.1, mas é uma mentira e só funcionará no .NET Framework e .NET Core por causa do acoplamento estreito que temos. Nós o hackeamos para funcionar, jogando truques InternalsVisibleTo para dar acesso aos construtores do TypeInfo, mas esse mesmo truque é o que o faz não funcionar em uma plataforma .NET Standard geral. Decidimos não propagar mais o erro hackeando o netstandard2.0 da mesma forma e, em vez disso, paramos de produzir o pacote e o tornamos específico para a plataforma.

Obrigado por levantar o problema @svick e devemos usar esse problema para documentar o problema com o pacote.

Que tal retirar da lista os pacotes não mais atualizados no NuGet para que fique claro que não são recomendados?

Essa é uma sugestão razoável. Acabei de remover a lista de todas as versões de https://www.nuget.org/packages/System.Reflection.Emit/ e https://www.nuget.org/packages/System.Reflection.Emit.Lightweight

Isso é muito necessário. Não ser capaz de construir e salvar assemblies é atualmente meu maior bloqueador dotnet / corefx # 1 para atualização para .NET Core, e eu realmente gostaria de ver tornar esta API fundamental em alta velocidade tornada uma prioridade mais alta do que trabalhar em novos recursos .

@masonwheeler apenas para

@weshaggard tem certeza? Acabei de verificar o repo e parece que não apenas AssemblyBuilder.Save ainda não foi implementado, como ainda nem existe no Core! (Posso estar errado; estou no meu telefone e a interface móvel do GitHub não é a melhor, mas é o que parece.)

@masonwheeler você está correto ao dizer que não oferecemos suporte a AssemblyBuilder.Save no .NET Core que está sendo rastreado por outro problema https://github.com/dotnet/corefx/issues/4491.

Aí está! Eu pensei que já tinha visto esse problema antes, mas pesquisar apenas revelou este. : P

Mas sim. Sem a capacidade de realmente emitir seus resultados, você não pode realmente dizer que pode usar o Reflection.Emit on Core. ☹️

@weshaggard antes do pacote System.Reflection.Emit.Lightweight ser não listado no nuget.org, era possível obter o pacote Selenium.WebDriver no PowerShell 5 (para .Net Framework) e PowerShell Core 6 (para .Net Core 2.0) no Windows 10 usando o seguinte comando: Install-Package Selenium.WebDriver -Destination $ PSScriptRoot -Force -ForceBootstrap

Agora, este comando não pode baixar todas as dependências do pacote Selenium para ambas as versões do PowerShell. Ele falha porque o pacote System.Reflection.Emit.Lightweight.4.3.0 não está listado em nuget.org.
Erro: Install-Package: Incapaz de encontrar o (s) pacote (s) dependente (s) (System.Reflection.Emit.Lightweight)

Você poderia aconselhar sobre como corrigir esse problema?

@SergeyKhutornoy você está chamando "Install-Package" no VS do console do gerenciador de pacotes? Se for assim, instala corretamente o pacote para mim. Se você estiver chamando Install-Package do Powershell, esse é um tipo diferente de gerenciamento de pacotes. Na verdade, tentei fazer isso localmente e recebo um erro diferente (Install-Package: Nenhuma correspondência foi encontrada para os critérios de pesquisa especificados e o nome do pacote 'Selenium.WebDriver'.) Não estou familiarizado com esse sistema de gerenciamento de pacotes, portanto não tenho certeza de como contornar isso. Uma coisa que você pode tentar é instalar explicitamente o System.Reflection.Emit.Lightweight 4.3.0 primeiro e depois ver se funciona. Se isso não funcionar, há um motivo pelo qual você não pode usar as ferramentas VS ou nuget para instalar o pacote?

Cancelar a lista deste pacote é um erro, e não fornecer uma versão .NET Standard 2.0 é um erro.

Estamos prestes a lançar uma nova versão importante de nosso produto, NServiceBus, e nosso objetivo é netstandard2.0 . Também temos uma dependência de System.Reflection.Emit e System.Reflection.Emit.Lightweight. Minha intenção original era direcionar o .NET Framework e o .NET Core separadamente, mas uma conversa no Twitter com @terrajobst combinada com a descoberta de que esses pacotes estavam disponíveis me levou a mudar de planos e direcionar para netstandard2.0 .

Não me importo de não poder salvar tanto assemblies dinâmicos - sempre posso testar a lógica em um .NET Framework TFM - mas DynamicMethod é incrivelmente útil e amplamente usado para gerar thunks de reflexão, delegados de conversão etc. Os pacotes. System.Reflection.Emit. * Têm mais de 20 milhões de downloads.

Traga de volta uma forma de referenciar DynamicMethod nas bibliotecas netstandard2.0.

Como usamos DynamicMethod no .NET Core agora que ele não está listado como um pacote?

@danielcrenna Você não precisa do pacote para usar DynamicMethod no .Net Core, uma vez que está embutido. Você só precisava do pacote para usá-lo no .Net Standard.

Eu poderia construir meu runtime (que já foi lançado) em .netstandard 2.0 usando System.Reflection.Emit.Lightweight 4.3 como uso DynamicMethod. Agora vejo que o processo de compilação extrai o pacote do cache offline e não do nuget. ~ Se o cache offline estiver hospedado, não posso construir o código novamente para .NETstandard. ~ (Hosing o cache faz com que o processo de construção extraia o pacote novamente, pois o pacote ainda está lá, embora não listado, então não é um obstáculo tecnicamente. É semanticamente embora).

Olhando aqui: https://apisof.net/catalog/System.Reflection.Emit.DynamicMethod qual é a conclusão que devo tirar? Isso está em NS1.6? Ou em alguma dimensão intermediária onde 'extensões de plataforma' são válidas?

Então, iow: Como eu viso .netstandard2.0 e uso DynamicMethod, posso fazer uma referência a System.Reflection.Emit.Lightweight embora não esteja listado e seja compatível com ns1.6 (?), Mas isso parece muito estranho: parece que uma responsabilidade, pois agora dependo de um pacote que não está listado (e então tenho que esperar que os pacotes não listados sejam mantidos lá até o fim dos tempos). O triste é: não há alternativa a não ser depender de um pacote não listado que só é possível porque um sabe o nome exato.

// @terrajobst

Para adicionar: EF Core 2.1 tem uma dependência de Castle.Core (https://www.nuget.org/packages/Castle.Core/) para seus proxies, que depende de System.Reflection.Emit.

Não é sensato para todos os envolvidos ter este pacote (e Emit.Lightweight) para simplesmente serem alistados novamente?

@FransBouma estritamente falando, EF Core Proxies tem a dependência, não o EF Core em si. Mas é uma bagunça de qualquer maneira.

Na verdade, _FirebirdClient_ depende de _System.Reflection.Emit_. E o que fazer agora, certo?

Embora seja compreensível que plataformas AOT completas não possam permitir que novos tipos sejam gerados em tempo de execução, é mais surpreendente que não possamos oferecer suporte a System.Reflection.Emit.Lightweight nessas plataformas.
LambdaExpression.Compile() funciona em todas as plataformas, mesmo se for interpretado em AOT.

Eu sou o autor da biblioteca LightInject DI e que está usando Reflection.Emit e DynamicMethod para gerar código em tempo de execução. Isso foi bom até que essas outras plataformas começaram a surgir. SilverLight, WinRT, iOS e assim por diante. Então o que fazer? O que fiz foi "shim" os DynamicMethod para que os OpCodes sejam traduzidos em expressões. Existe uma espécie de relação 1-1 entre Opcodes e expressões, então isso não é tão difícil.

Dê uma olhada aqui para a implementação.
https://github.com/seesharper/LightInject/blob/a01be40607761d9b446dc4acad37d7f717742975/src/LightInject/LightInject.cs#L4483

Observe que eu não implemento todos os Opcodes. Só os que preciso.

Meu ponto é que deveria ser possível fazer isso para todos os OpCodes e então habilitar MUITAS bibliotecas para ainda direcionar netstandard2.0. A maioria das bibliotecas que usa Reflection.Emit não gera novos tipos. Eles simplesmente geram código por meio do DynamicMethod

Observe também que DynamicProxy, Moq e outras bibliotecas que geram tipos em tempo de execução não podem ter como destino netstandard2.0 . Eles devem ser netcoreapp pois basicamente dependem de AssemblyBuilder com amigos
Portanto, o ponto principal é que o pacote System.Reflection.Emit.Lightweight nunca pode ser removido inteiramente do NuGet como netstandard2.0 . Essa seria a história do LeftPad novamente

Meus dois centavos

Existe um lugar lista dos MFT que apoiar System.Reflection.Emit ? Acabei de adicionar net45 e netcoreapp2.0 TFMs explícitos ao meu projeto, mas tenho certeza de que estou faltando alguns.

@jbogard Todos os

Esta parece ser uma decisão mal pensada e comunicada com consequências de longo alcance que parece ter sido feita com muito pouco envolvimento da comunidade que afeta, o que é surpreendente, dado que os pacotes têm 22 milhões de downloads. Isso não justifica algum tipo de análise sobre o impacto potencial em todos que atualmente dependem dele?

ServiceStack faz referência aos pacotes Reflection.Emit agora removidos em ServiceStack.Text, que é o pacote de dependência básico usado em todos os pacotes NuGet do ServiceStack , bem como vários outros pacotes NuGet usando-o como uma dependência. Nós fornecemos apenas netstandard2.0 e net45 builds, forçando a segmentação da plataforma .netcore quebraria todas as dependências e todos os projetos netstandard2.0 usassem - ou seja, a estrutura de destino preferida para a criação de plataforma cruzada compilações que oferecem suporte ao .NET Framework e ao .NET Core.

Então, qual é a recomendação agora para pacotes usando Reflection.Emit? Parar de publicar compilações .NET Standard 2.0 e dizer a todos que não podem mais criar compilações .NET Standard 2.0 para suas bibliotecas e projetos?

A solução anterior para usar APIs .NET Standard que não implementam a API era lançar PlatformNotSupportedException exceções de tempo de execução, por que exatamente essa não é a solução aqui?

@seesharper sim, eu adicionei aqueles, mas isso pode deixar outros de fora. Os documentos da API listam mais, mas o que outros podem estar faltando? É uma lista abrangente de possíveis TFMs que suportam a API? Que tal, digamos, xamarinxboxone ?

Refatorei meu código DynamicMethod / ILGenerator que usei para emitir métodos setter para propriedades em tempo de execução com uma solução Lambda.Compile (), então a dependência de Reflection.Emit acabou, no entanto, tive que gastar 3-4 horas nisso que eu gostaria de ter gasto em outras coisas. Mas, infelizmente, é a vida quando as coisas 'andam rápido e quebram com frequência', eu acho?

De qualquer forma, o que acho um pouco perturbador é o silêncio ensurdecedor do pessoal da Microsoft neste tópico nas últimas semanas. Dá vontade de debater coisas em uma sala quando as pessoas que realmente podem mudar as coisas não estão lá.

Eu concordo totalmente com @mythz e outros aqui, é mal comunicado, e com 22 milhões de downloads esta foi uma decisão boba com consequências de longo alcance.

@mythz Eu não sei como você está usando isso, mas para minhas coisas, eu tive que voltar para #if sinalizadores de recurso para remover funcionalidade em plataformas que não suportam tipos de construção em tempo real (em minha biblioteca, sendo capaz de mapear para uma interface e criar um proxy na hora).

@jbogard Usamos um sinalizador booleano Env.SupportsEmit para determinar em tempo de execução se a plataforma suporta Reflection.Emit, se tiver, nós o usamos, caso contrário, recorreremos a Expressões Compiladas. Por falar nisso, seria útil se houvesse um sinalizador Platform.SupportsEmit que todos pudessem usar para verificar se a plataforma em execução suporta Reflection.Emit.

A diretiva #if exigiria a criação de múltiplas compilações de plataforma, o que seria a causa da alteração decisiva para todos os pacotes e projetos dependentes que visam .netstandard2.0 , uma vez que também requerem dependências .netstandard2.0 .

Apenas para uma discussão mais aprofundada, gostaria de garantir que estamos todos na mesma página no que diz respeito à diferença entre System.Reflection.Emit e System.Reflection.Emit.Lightweight .

Na verdade, esse problema deveria ter sido dividido em dois problemas separados. 😄

  • Deve haver uma versão .Net Standard 2.0 do Reflection.Emit?
  • Deve haver uma versão .Net Standard 2.0 de System.Reflection.Emit.LightWeight?

System.Reflection.Emit

Este pacote contém AssemblyBuilder e classes relacionadas que precisamos para gerar assemblies / tipos em tempo de execução.
O problema com este pacote é que ele nunca deveria ter sido colocado no NuGet como um pacote netstandard , pois a geração de novos tipos em tempo de execução não pode ser suportada em plataformas AOT completas.
Meu palpite é que a Microsoft adicionou isso como um pacote netstandard para facilitar a migração do framework completo para .Net Core e bibliotecas netstandard . Em retrospectiva, não é realmente a melhor ideia.
A abordagem "isca e troca" (entendida por 5 pessoas em todo o mundo) também não é uma grande solução.

System.Reflection.Emit.LightWeight

Este pacote contém o DynamicMethod que torna possível compilar código dinamicamente SEM criar novos tipos. O "método dinâmico" é basicamente um método estático para o qual podemos criar um delegado usado para invocar o método.
LambdaExpression.Compile é basicamente o mesmo ting e se olharmos para a implementação no framework completo, veremos que ele realmente usa DynamicMethod baixo dos panos.
O fato é que LambdaExpression.Compile() funciona em todas as plataformas usando interpretação em AOT. Por causa disso, não há razão para que não possamos criar um pacote System.Reflection.Emit.LightWeight que seja netstandard usando a técnica que descrevi anteriormente neste tópico.

Meu palpite é que a razão para retroceder nisso agora é garantir que o padrão realmente dê algum significado no futuro. O problema, a meu ver, é que podemos ver pacotes de biblioteca visando netcoreapp vez de netstandard e isso seria muito ruim quando se trata de desenvolver todo o conceito de um netstandard .

Minha sugestão é fazer um esforço para publicar System.Reflection.Emit.LightWeight como um pacote netstandard verdadeiro e continuar a empurrar para netcoreapp quando se trata de System.Reflection.Emit .

@seesharper Pelo que eu sei, Reflection.Emit (incluindo Reflection.Emit.Lightweight) é usado principalmente para desempenho. Mas se você implementou Reflection.Emit.Lightweight usando um interpretador IL, seu desempenho provavelmente seria muito ruim. Portanto, não estou convencido de que o esforço de apoiar o modo de interpretação IL em Reflection.Emit.Lightweight seria justificado.

Também é estranho que System.Reflection.Emit.ILGenerator ainda esteja listado (https://www.nuget.org/packages/System.Reflection.Emit.ILGeneration), pois é um pacote netstandard1.6, no entanto ILGenerator não tem implementação UWP (https://apisof.net/catalog/System.Reflection.Emit.ILGenerator).

Iow: um pouco bagunçado, não é?

@seesharper Boa sugestão.

@svick Não acho que seja justificativa suficiente para cortá-lo. Linguagens específicas de domínio precisam de um recurso para construir código em tempo de execução. DSLs surgem com freqüência suficiente em projetos maiores ( Invoke ). Se for um componente padrão, pelo menos as partes "especificadas informalmente e repletas de bugs" da regra seriam mitigadas. Quanto ao desempenho de uma implementação de segmentação AOT, não precisa ser um interpretador IL. Mesmo em plataformas que não permitem que um processo crie páginas de memória executáveis, pode-se compilar métodos dinâmicos para código encadeado como muitas implementações FORTH fazem, e para pequenos métodos dinâmicos onde o "corpo do método" se encaixa em algumas linhas de cache, o a sobrecarga de tempo de execução deve ser bastante baixa.

O problema com este pacote é que ele nunca deveria ter sido colocado no NuGet como um pacote netstandard, uma vez que a geração de novos tipos em tempo de execução não pode ser suportada em plataformas AOT completas.

Discordo. As principais plataformas .NET Core e .NET Framework o suportam, só porque os ambientes AOT não devem impedir que ele seja capaz de oferecer suporte às principais plataformas .NET direcionadas a netstandard2.0 .

Isso agora se tornou a estratégia para o futuro do .NET Standard? APIs não suportadas em ambientes AOT agora serão removidas? Portanto, não haverá mais exceções PlatformNotSupportedException , as APIs serão puxadas em vez de voltar para um subconjunto PCL? Ou seremos inconsistentes e reduziremos seletivamente a superfície da API para alguns recursos, mas continuaremos adicionando outros?

Apoiar a interseção das APIs de menor denominador comum foi o que o PCL fez e resultou em uma experiência de desenvolvimento horrível que forçou a isca PCL e a técnica de troca e delegação para várias implementações específicas da plataforma, que é todo o investimento que jogamos fora quando mudamos para. NET Standard.

A melhor solução era a existente (especialmente porque removê-la agora é uma mudança disruptiva e interrompida em suas dependências transitivas) que nos permite usar Reflection.Emit em todas as plataformas que o suportavam, embora precisando implementar um fallback para aquelas que não . Remover a capacidade de usar Reflection.Emit no .NET Standard significa que as bibliotecas que o usam não podem mais ter como alvo o .NET Standard. Qual é mesmo o ponto se não podemos usar recursos que o .NET Core e o .NET Framework compartilham em uma abstração independente de plataforma? Seria apenas adicionar abstrações / confusão / complexidade desnecessárias ao ecossistema .NET sem benefícios.

Obrigado a todos pelo feedback. Com base no feedback esmagador, relistamos a versão mais recente dos pacotes existentes:

https://www.nuget.org/packages/System.Reflection.Emit/4.3.0
https://www.nuget.org/packages/System.Reflection.Emit.Lightweight/4.3.0

No entanto, conforme mencionado anteriormente neste tópico, esses pacotes afirmam ser compatíveis com o netstandard1.1, mas isso é uma mentira. Eles funcionarão apenas no .NET Core e .NET Framework. Portanto, se você os estiver consumindo de uma biblioteca netstandard, espere que essa biblioteca falhe se for executada em qualquer outra implementação .NET Standard.

Ainda não temos uma ótima solução para suportá-los no netstandard2.0, mas os proprietários ( @AtsushiKan @joshfree) do System.Relfection.Emit tentarão descobrir a solução de longo prazo.

@svick

Pelo que eu sei, Reflection.Emit (incluindo Reflection.Emit.Lightweight) é usado principalmente para desempenho. Mas se você implementou Reflection.Emit.Lightweight usando um interpretador IL, seu desempenho provavelmente seria muito ruim. Portanto, não estou convencido de que o esforço de apoiar o modo de interpretação IL em Reflection.Emit.Lightweight seria justificado.

É meu entendimento que LambaExpression.Compile() e sua execução são interpretados em plataformas AOT e, portanto, não deveria ser pior fazê-lo para System.Reflection.Emit.LightWeight .
Existem muitas bibliotecas usando este pacote e ter um pacote netstandard2.0 "verdadeiro" permitiria repentinamente que esses pacotes rodassem em seu iPhone sem forçar os desenvolvedores desses pacotes a reescrever seu código para corresponder às diferentes plataformas. O desempenho seria prejudicado, mas funcionaria exatamente como hoje com LambdaExpression.Compile()

@mythz

Isso agora se tornou a estratégia para o futuro do .NET Standard? APIs não suportadas em ambientes AOT agora serão removidas? Portanto, não haverá mais exceções PlatformNotSupportedException, as APIs serão puxadas em vez de voltar a um subconjunto PCL? Ou seremos inconsistentes e reduziremos seletivamente a superfície da API para alguns recursos, mas continuaremos adicionando outros?

IMHO, lançar PlatformNotSupportedException é apenas outra manifestação do subconjunto de API que vimos com PCLs. Como o caso é com System.Reflection.Emit.LightWeight , podemos realmente implementá-lo e não há razão para lançar um PlatformNotSupportedException . No entanto, concordo que é problemático que plataformas menos capazes impeçam o padrão de avançar. Mas essa é a natureza de se ter um padrão. Quando são feitos acréscimos ao padrão, deve-se garantir que seja pelo menos de alguma forma possível implementar pelas plataformas que implementam o padrão. Pelo menos entre os grandes jogadores e diria que Xamarin se encaixa nessa categoria.

Esta figura, tal como está hoje, é uma espécie de mentira, a meu ver. Xamarin afirma apoiar netstandard , mas esse suporte está repleto de exceções que para nós podem parecer razoáveis. Para o novato, pode não ser tão fácil de entender.

image

@weshaggard

Continuar a publicar System.Reflection.Emit como um pacote netstandard não é uma boa solução a longo prazo. Isso torna o padrão "falso" novamente e só deve estar disponível para net / netcoreapp. É uma pílula difícil de engolir, acredite, eu sei. Eu tenho exatamente o mesmo problema com 'LightInject.Interception' que é uma biblioteca de proxy usando System.Reflection.Emit . Mas prefiro ter como alvo netcoreapp vez de mentir para o consumidor que essa biblioteca pode ser executada em qualquer lugar.

@seesharper

IMHO, lançar PlatformNotSupportedException é apenas outra manifestação do subconjunto de API que vimos com PCLs. Como é o caso com System.Reflection.Emit.LightWeight, podemos realmente implementá-lo e não há razão para lançar uma PlatformNotSupportedException.

Eles não são equivalentes de forma alguma. A única razão pela qual o .NET Standard é útil é devido à sua superfície de API muito maior, que nos permite criar um único build para rodar em múltiplas plataformas. Os PCLs são muito menos úteis, pois seu subconjunto reduzido de interseção de API forçou a criação de múltiplas compilações específicas de plataforma para funcionalidade não trivial. Suas capacidades não são equivalentes e as soluções às quais levam são muito diferentes em complexidade para autores e consumidores de bibliotecas. Com o .NET Standard, temos um único build que roda em todas as plataformas, pois podemos verificar em tempo de execução se a plataforma suporta Reflection.Emit, se não, recuamos para Lambda Expressions and Reflection. Se essas APIs não estivessem disponíveis para bibliotecas .NET Standard, não poderíamos ter uma única compilação e precisaríamos voltar a desenvolver e manter compilações específicas de plataforma não portáteis.

Continuar a publicar System.Reflection.Emit como um pacote netstandard não é uma boa solução a longo prazo. Isso torna o padrão "falso" novamente e só deve estar disponível para net / netcoreapp.

Forçar a criação e dependência de compilações específicas da plataforma é um resultado muito pior, esp. com tantas dependências transitivas já dependentes dele. O principal benefício do .NET Standard é ser capaz de criar bibliotecas e projetos para direcionar uma única abstração útil; se não pudermos usá-lo para acessar os recursos principais disponíveis no .NET Core e .NET Framework, ele falhará em resolver seu uso principal -caso e também pode não existir, pois está apenas adicionando mais abstrações / confusão ao ecossistema .NET, sem quaisquer benefícios sobre os PCLs.

O PCL já tentou vincular a abstrações que apenas expõem a interseção dos recursos da API disponíveis em cada plataforma, que é efetivamente o que você está pedindo, já que você só terá acesso às APIs disponíveis em cada plataforma e, por extensão, conterá apenas APIs disponível na plataforma mais restrita.

Ter uma API de superfície mais ampla no .NET Standard é muito mais útil e dá aos autores de bibliotecas a liberdade de escolher como desejam lidar com o suporte para diferentes plataformas. Se essas APIs não estivessem disponíveis, essa opção não existiria, forçar compilações específicas da plataforma e forçar todas as suas bibliotecas e projetos dependentes a também manter compilações específicas da plataforma, adicionando atrito, fragmentação, reduzindo a portabilidade e limitando o suporte apenas para as plataformas que os autores escolheram para manter compilações para todas as plataformas que suportam o .NET Standard que suportam esse recurso.

Não é apenas uma questão de preferência, remover o suporte à API mainstream tem um impacto disruptivo de longo alcance sobre quais soluções estão disponíveis, força compilações específicas de plataforma desnecessárias que afetam a utilidade das bibliotecas enquanto quebra todas as bibliotecas e projetos do .NET Standard que as usam.

@weshaggard

Ainda não temos uma ótima solução para suportá-los no netstandard2.0, mas os proprietários ( @AtsushiKan @joshfree) do System.Relfection.Emit tentarão descobrir a solução de longo prazo.

Que tal dizer aos iDiots e maníacos por controle que forçam somente AOT em todos que usam suas plataformas que eles precisam ajustar e corrigir suas regras de plataforma ruins? (Porque vamos ser honestos, todos nós sabemos que isso realmente se trata: alguns malfeitores muito específicos no mundo móvel.)

@mythz você está absolutamente certo.

@masonwheeler

Eu entendo perfeitamente que esconder o pacote ref emit é frustrante, considerando a queda que ele causou. Eu também entendo que a otimização para ambientes de execução com os quais você não se importa pode ser perturbadora, especialmente quando isso inclui compensações que afetam os cenários com os quais você se preocupa negativamente.

Dito isso, marquei seu comentário como "abusivo", pois não é construtivo. Insultar as pessoas não resolverá essas questões. Considere também que esta não é uma política que controlamos. O fato de você não poder gerar e executar código em tempo de execução no iOS é uma decisão política da Apple. Além disso, em alguns casos, não é uma restrição de política, mas tecnológica.

Existem três opções com emissão de reflexão:

  1. Corrija os pacotes atuais e faça-os funcionar com base no .NET Standard 2.0 . O problema é uma estranha relação de herança entre Type e TypeInfo no .NET Standard 1.x em comparação com 2.0 e ter construtores não públicos. Posso entrar em mais detalhes, mas para tornar o pacote realmente compilável sem restaurar para hacks é um pouco complicado, e é por isso que originalmente decidimos ocultar os pacotes.

  2. Adicione a emissão de reflexão ao .NET Standard vNext . Para oferecer suporte a cenários somente AOT, isso provavelmente incluiria uma API de capacidade que permite aos consumidores verificar se a geração de código é compatível ou eficiente (ou seja, se usamos execução real em oposição à interpretação).

  3. Não expor a reflexão, emite para .NET Standard e exige que os autores da biblioteca tenham vários alvos . Esse era basicamente o caminho original quando começamos a ocultar o pacote.

No momento, estamos inclinados para a primeira opção, mas a segunda opção também está na mesa.

Sou a favor de 2. É onipresente o suficiente para estar lá. Precisamos da verificação de capacidade de qualquer maneira por outros motivos.

Sou a favor de 2. É onipresente o suficiente para estar lá. Precisamos da verificação de capacidade de qualquer maneira por outros motivos.

Eu também, mas não ajudará ninguém que esteja atualmente contando com o .NET Standard 2.0, pois isso requer uma nova versão do padrão. No entanto, as APIs em questão já existem.

Portanto, estou pensando em uma correção mínima para fazer esses pacotes funcionarem como estão, mas também corrigir o .NET Standard 2.0 vNext.

@terrajobst Existe algo na opção 1 que torna a opção 2 mais difícil de fazer? Parece-me que obter uma versão dos pacotes que visam netstandard2.0 vez de precisar puxar o gráfico de pacote netstandard1.1 seria uma boa meta de curto prazo. Então, para o vNext do padrão, ele poderia se tornar parte dele e você não precisaria mais dos pacotes.

Portanto, a menos que haja um bom motivo para não fazê-lo, voto em 1 e 2.

@bording

Parece que postamos praticamente ao mesmo tempo. Espero que meu comentário responda à sua pergunta :-)

Observe que netstandard2.0 suporta System.Reflection.Assembly.Load(byte[] rawAssembly) método estático, que carrega um assembly da matriz de bytes de imagem binária. Isso significa que é possível implementar não todos, mas a maioria dos System.Reflection.Emit APIs compatíveis com netstandard2.0 puros.

(Desculpe, não sei quantas plataformas suportam Assembly.Load sem PNSE)

@GlassGrass a quais frameworks você imagina que uma implementação netstandard2.0 se aplicaria?

Certamente posso imaginar alguma implementação que escreveria o IL e produziria um assembly como um ILASM orientado por API, mas não vejo estruturas atuais onde eu gostaria de usar isso.

Frameworks que têm um JIT (e suportam Assembly.Load) também podem suportar Ref.Emit diretamente e fornecer sua implementação Ref.Emit em vez de uma versão netstandard2.0. Eu sei que este é o caso, pelo menos, desktop / .netcore / .netnative. Os dois primeiros suportam ref.emit e fornecem uma implementação, o último não tem, nem tem um JIT nem suporta carregamento dinâmico de montagem.

Eu realmente acho que seria um projeto interessante para alguém brincar no corefxlab para escrever algo em cima de System.Reflection.Metadata que se pareça com Ref.Emit (ou melhor). Não tenho certeza se alguém já está olhando para isso. / cc @nguerrera @tmat

Eu acho que seria um projeto interessante para alguém brincar no corefxlab para escrever algo em cima de System.Reflection.Metadata que se pareça com Ref.Emit (ou melhor).

Isso está no meu prato: (https://github.com/dotnet/corefx/issues/4491 e https://github.com/dotnet/corefx/issues/2800)

https://github.com/dotnet/corefx/issues/2800 virá primeiro, já que o material de emissão ref é provavelmente uma extensão dele. Comecei a fazer o protótipo de 2800 esta semana e irei continuar esse trabalho nos próximos meses. Não vou movê-lo para o corefxlab até que esteja muito mais longe. O fluxo de trabalho é muito ineficiente para o meu gosto.

@AtsushiKan : Fico feliz em ver que ainda há um trabalho em andamento nessa questão. Obrigado por resolver isso.

Mencionei o seguinte em outro lugar anteriormente: Uma coisa que System.Reflection.Metadata e Assembly.Load(byte[]) não podem fazer é a emissão incremental tipo por tipo. Você não pode emitir um tipo, depois outro ... você só pode emitir assemblies completos, o que significa que isso não é muito útil, por exemplo, para simular bibliotecas que dependem da geração de tipo proxy dinâmico.

É claro que só se poderia produzir assemblies de tipo único, mas isso se torna potencialmente ineficiente e difícil ao tornar os internos visíveis para os assemblies gerados dinamicamente por meio de [assembly: InternalsVisibleTo] (outra coisa que as bibliotecas de simulação / teste geralmente exigem). Você teria que ser capaz de dar a vários assemblies dinâmicos de tipo único a mesma identidade / nome forte para que isso funcionasse. (O tempo de execução já pode permitir isso na prática, mas não consigo encontrar a documentação oficialmente confirmando isso.)

@stakx Você pode emitir System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute para o assembly dinâmico para permitir que ele acesse membros não públicos do assembly especificado, em vez de usar o IVT.

@tmat : Isso é interessante. Este atributo está oficialmente documentado em algum lugar?

É uma pena que esse atributo especial não esteja oficialmente documentado, meio que torna um pouco arriscado usá-lo fora do tempo de execução.

Isso seria adicionado a .NET core 3.0 ?

cc @steveharter @joshfree

@karelz https://github.com/dotnet/corefx/issues/30654 acompanha o trabalho para 3.0

@joshfree é um

@karelz cobriu o problema com o pacote Ref.Emit sendo incorretamente retirado do nuget e então o pacote sendo re-listado por @weshaggard. Eu acho que este problema pode ser resolvido já que o trabalho restante é rastreado com dotnet / corefx # 30654.

OK, fechando então :) ... o trabalho restante é rastreado em dotnet / corefx # 30654 como mencionado acima.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Timovzl picture Timovzl  ·  3Comentários

noahfalk picture noahfalk  ·  3Comentários

matty-hall picture matty-hall  ·  3Comentários

jkotas picture jkotas  ·  3Comentários

nalywa picture nalywa  ·  3Comentários