| Severity | Error |
| Reported by | Metalama.Framework |
| Message | Execution scope mismatch in the expression '<ParentExpression>': the type of the expression is <ParentScope>, but the sub-expression '<ChildExpression>' is <ChildScope>. |
Cause
In a T# template, Metalama classifies every expression as either compile-time, which it evaluates while generating the code, or run-time, which it copies into the generated code. The scope of an expression depends on its sub-expressions, but also on its type: an expression of a run-time-only type, such as a type defined in your project, can only exist at run time, while an expression of a compile-time type, such as IParameter, can only exist at compile time.
Metalama reports LAMA0242 when the sub-expressions of an expression agree on a scope, but the type of the expression requires the other scope. The message gives the scope of the type and the sub-expression that conflicts with it. This typically happens when you apply the as operator to a compile-time object, such as an IParameter, while you meant to apply it to the run-time value that the object represents.
In the following example, the aspect checks whether the first argument of the method is a Customer, but it applies the as operator to the compile-time parameter instead of the argument value.
1using Metalama.Framework.Aspects;
2
3namespace Doc.LAMA0242.Error;
4
5public class LogCustomerAttribute : OverrideMethodAspect
6{
7 public override dynamic? OverrideMethod()
8 {
9 // Error: the run-time 'as' operator is applied to the compile-time IParameter, not to the argument value.
Error LAMA0242: Execution scope mismatch in the expression 'meta.Target.Parameters[0] as Customer': the type of the expression is run-time, but the sub-expression 'meta.Target.Parameters[0]' is compile-time.
10 var customer = meta.Target.Parameters[0] as Customer;
11
12 return meta.Proceed();
13 }
14}
15
1namespace Doc.LAMA0242.Error;
2
3public class Person
4{
5 public string Name { get; set; } = "";
6}
7
8public class Customer : Person
9{
10 public int LoyaltyPoints { get; set; }
11}
12
13internal class OrderService
14{
15 [LogCustomer]
16 public void PlaceOrder( Person buyer, int quantity ) { }
17}
18
Resolution
Make the sub-expression match the scope of the expression type. To work with the run-time value of a parameter, field, or property, use its Value property, which is a run-time expression of type dynamic. The following example applies the as operator to meta.Target.Parameters[0].Value.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0242.Fixed;
5
6public class LogCustomerAttribute : OverrideMethodAspect
7{
8 public override dynamic? OverrideMethod()
9 {
10 // Fixed: the 'as' operator is applied to the run-time value of the parameter.
11 var customer = meta.Target.Parameters[0].Value as Customer;
12
13 if ( customer != null )
14 {
15 Console.WriteLine( $"Customer {customer.Name} has {customer.LoyaltyPoints} loyalty points." );
16 }
17
18 return meta.Proceed();
19 }
20}
21
1namespace Doc.LAMA0242.Fixed;
2
3public class Person
4{
5 public string Name { get; set; } = "";
6}
7
8public class Customer : Person
9{
10 public int LoyaltyPoints { get; set; }
11}
12
13internal class OrderService
14{
15 [LogCustomer]
16 public void PlaceOrder( Person buyer, int quantity ) { }
17}
18
1using System;
2
3namespace Doc.LAMA0242.Fixed;
4
5public class Person
6{
7 public string Name { get; set; } = "";
8}
9
10public class Customer : Person
11{
12 public int LoyaltyPoints { get; set; }
13}
14
15internal class OrderService
16{
17 [LogCustomer]
18 public void PlaceOrder(Person buyer, int quantity)
19 {
20 var customer = buyer as Customer;
21 if (customer != null)
22 {
23 Console.WriteLine($"Customer {customer.Name} has {customer.LoyaltyPoints} loyalty points.");
24 }
25 }
26}
27