Question

Lorsque vous essayez de compiler une expression dans une fiducie moyenne application web Je reçois MethodAccessException. Quelqu'un sait-il d'une autre façon de compiler une expression en confiance moyenne ou une solution de contournement pour éviter cette exception?

Le code qui lève l'exception:

Expression<Func<object>> efn = 
  Expression.Lambda<Func<object>>(Expression.Convert((plan,typeof(object)));

Func<object> fn = efn.Compile(); // Exception thrown here

Le plan variable est une expression qui représente le plan d'exécution suivant:

{
  Convert(Query(MyProjectNamespace.MyDatabaseTableObject).Provider).Execute
  (
    new QueryCommand(
    "SELECT [t0].[LinkId], [t0].[Url] FROM [dbo].[MyDatabaseTable] AS t0",
    value(System.String[]), 
    r0 => new MyDatabaseTableObject() 
    {
      Id = IIF(r0.IsDBNull(0), 0, 
        Convert(ChangeType(r0.GetValue(0), System.Int32))), 
      Url = IIF(r0.IsDBNull(1), null, 
        Convert(ChangeType(r0.GetValue(1), System.String)))
    }, 
    value(System.Collections.Generic.List[System.String])), 
    new [] {}
  )
}

Le plein trace de la pile:

at System.Reflection.MethodBase.PerformSecurityCheck(Object obj, RuntimeMethodHandle method, IntPtr parent, UInt32 invocationFlags)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Linq.Expressions.ExpressionCompiler.AddGlobal(Type type, Object value)
at System.Linq.Expressions.ExpressionCompiler.GenerateConstant(ILGenerator gen, Type type, Object value, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConstant(ILGenerator gen, ConstantExpression c, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateArgs(ILGenerator gen, ParameterInfo[] pis, ReadOnlyCollection`1 args)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodInfo mi, ReadOnlyCollection`1 args, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodCallExpression mc, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConvert(ILGenerator gen, UnaryExpression u)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConditional(ILGenerator gen, ConditionalExpression b)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateMemberAssignment(ILGenerator gen, MemberAssignment binding, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateBinding(ILGenerator gen, MemberBinding binding, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMemberInit(ILGenerator gen, ReadOnlyCollection`1 bindings, Boolean keepOnStack, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMemberInit(ILGenerator gen, MemberInitExpression init)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateLambda(LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.GenerateCreateDelegate(ILGenerator gen, LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateArgs(ILGenerator gen, ParameterInfo[] pis, ReadOnlyCollection`1 args)
at System.Linq.Expressions.ExpressionCompiler.GenerateNew(ILGenerator gen, NewExpression nex, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateArgs(ILGenerator gen, ParameterInfo[] pis, ReadOnlyCollection`1 args)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodInfo mi, ReadOnlyCollection`1 args, Type objectType)
at System.Linq.Expressions.ExpressionCompiler.GenerateMethodCall(ILGenerator gen, MethodCallExpression mc, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateConvert(ILGenerator gen, UnaryExpression u)
at System.Linq.Expressions.ExpressionCompiler.Generate(ILGenerator gen, Expression node, StackType ask)
at System.Linq.Expressions.ExpressionCompiler.GenerateLambda(LambdaExpression lambda)
at System.Linq.Expressions.ExpressionCompiler.CompileDynamicLambda(LambdaExpression lambda)
at System.Linq.Expressions.Expression`1.Compile()
at SubSonic.Linq.Structure.DbQueryProvider.Execute(Expression expression)
at SubSonic.Linq.Structure.QueryProvider.System.Linq.IQueryProvider.Execute(Expression expression)
at SubSonic.Linq.Structure.Query`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at WebApplication1._Default.Page_Load(Object sender, EventArgs e)
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Était-ce utile?

La solution

Le problème sous-jacent est que le type étant passé à System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) est soit pas publique, ou a un constructeur qui ne sont pas publiques.

- étant donné la simplicité de votre exemple de code par rapport à la profondeur de la stacktrace Je crois que le problème ne réside pas dans plan, mais dans une expression au sein plan (puisque vous dites dans votre commentaire sur la réponse de Marc qu'il est aussi une expression) que les références du type qui est alors limité.

L'expression qui est la source de l'erreur ici est un ConstantExpression qui doit être du type restreint.

Toutefois, la confusion seule chose à ce sujet, est que l'argument de type qui passe à AddGlobal Activator.CreateInstance est StrongBox<T>, qui est public et a un constructeur public -. Qui impliquerait que cette erreur devrait être impossible

Peut-être, cependant, il y a quelque chose de caché associé à StrongBox<T> que nous ne pouvons voir à travers réflecteur.

Alors, je regarderais tout l'arbre d'expression représenté par plan et en examinant tous les types mentionnés dans ConstantExpressions pour vous assurer qu'ils sont tous accessibles. Si après avoir fait que tous les types sont présentés pour être accessibles, cette erreur se produit encore, alors il pourrait être un bug dans le cadre.

Cependant - j'aurais pensé qu'un tel bug aurait été trouvé déjà quelque chose d'aussi simple que ConstantExpression

EDIT (Remplacement de montage précédent) AVEC LA RÉPONSE

Je l'ai, et il est un problème très subtil. Vous pouvez reproduire avec ce petit bout de code dans une page ASPX qui est configuré pour fonctionner en fiducie moyen:

Type t = typeof([any type you fancy]);
Expression expr = Expression.Constant(t);
var lambda = Expression.Lambda<Func<Type>>(expr);
var del = lambda.Compile();
Response.Write(del().ToString());

Ainsi, dans le code que vous avez fourni, il est l'expression qui représente le second argument de ChangeType (m'a pris un certain temps pour se rendre compte que c'est un sous méthode Sonic), qui semble être un Type (ne peut pas voir la code, mais je pense que c'est une estimation raisonnable!).

Il est cuit dans l'expression comme ConstantExpression d'une instance de Type. Ne demandez pas comment je PRECISEE le paramètre - beaucoup de pile rampants et le travail de réflecteur;)

Comme mentionné dans la première moitié de ma réponse, il est difficile de voir comment le code que le compilateur arbre expression utilise peut jamais créer un MethodAccessException, car il est l'accès toujours cteur publique du type StrongBox<T>.

Cependant, il se fâcher si le type adopté en tant que générique n'est pas publique. "Mais attendez," vous dites: "Type est public!".

Ce pourrait être, mais l'instance de Type retourné lors de l'exécution de typeof() ou GetType() est pas - c'est une instance de RuntimeType - qui est interne

.

Quelle est la raison pour laquelle l'extrait de code ci-dessus déclenchera également la même erreur.

Le correctif

Modifier le code qui produit l'argument Type pour ChangeType(,) de

Expression.Constant([type])

(que je presque garantir qu'il est à l'heure actuelle) à

Expression.Constant([type], typeof(Type))

Cela fonctionne, parce que vous dites explicitement le compilateur d'utiliser le Type public pour la constante, au lieu du type de RuntimeType réfléchi.

Vous pouvez tester ce correctif en l'appliquant à mon exemple de code dans le bloc précédent et de refaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top