postsharp / Metalama

Metalama is a Roslyn-based meta-programming framework. Use this repo to report bugs or ask questions.
164 stars 4 forks source link

InvalidCastException #301

Closed wabluk closed 1 month ago

wabluk commented 1 month ago

I get the following Error when i use my Aspect:

System.InvalidCastException: Das Objekt des Typs "Metalama.Framework.Engine.CodeModel.Method" kann nicht in Typ "Metalama.Framework.Code.IFieldOrProperty" umgewandelt werden.
   bei Metalama.Extensions.DependencyInjection.IntroduceDependencyAttribute.BuildAdvice(IMemberOrNamedType templateMember, String templateMemberId, IAspectBuilder`1 builder) in C:\Users\lukas\AppData\Local\Temp\Metalama\CompileTime\Metalama.Extensions.DependencyIn\.netstandard2.0\980283e383500bb6\2024.1.19\IntroduceDe_27a18926.cs:Zeile 24.
   bei Metalama.Framework.Engine.Aspects.AspectDriver.<>c__DisplayClass7_1`1.<ExecuteAspect>b__3()
   bei Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.<>c__DisplayClass5_0.<TryInvoke>b__0()
   bei Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.Invoke[TResult,TPayload](UserCodeFunc`2 func, TPayload& payload, UserCodeExecutionContext context, Boolean wrapException)
   bei Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.Invoke[T](Func`1 func, UserCodeExecutionContext context, Boolean wrapExceptions)
   bei Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.TryInvoke[T](Func`1 func, UserCodeExecutionContext context, T& result)

Here is my Aspect Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Printplus.Extensions;
using Printplus.Logging.Aspects;
using Printplus.Translation;
using Printplus.Translation.Text;
using Printplus.Druck.Artikel.Entity;
using Printplus.Math.Round;
using System.Reflection;
using Printplus.Druck.Artikel.Contract;
using Printplus.Domain;
using Metalama.Framework.Aspects;
using Metalama.Extensions.DependencyInjection;
using Printplus.NotifyPropertyChanged;

namespace Printplus.Druck.Common.Aspects {

  [Serializable]
  [ExcludeAspect(typeof(TraceLoggingAttribute))]
  public class ArtikelRounderAttribute: OverrideFieldOrPropertyAspect {

    #region Fields

    private string _artikelPropertyName;

    #endregion Fields

    #region Constructors

    public ArtikelRounderAttribute(string artikelPropertyName) {
      _artikelPropertyName = artikelPropertyName;
    }

    #endregion Constructors

    #region Public Methods

    public override dynamic OverrideProperty {
      get {
        if (meta.Target.FieldOrProperty.Value != null) {
          string artikelID = GetArtikelID(meta.This);

          if (!string.IsNullOrEmpty(artikelID)) {
            IArtikelDomainController artikelDomainController = DomainControllerFactory.Instance.CreateDomainController<IArtikelDomainController>();
            ArtikelVO artikel = artikelDomainController.GetArtikelVOByID(artikelID);
            if (artikel != null) {

              return Rounder.Round((double)meta.Target.FieldOrProperty.Value, artikel.RundungsfaktorMengen, RounderType.Standard);
            }
          }
        }

        return meta.Target.FieldOrProperty.Value;
      }
      set {
        if (meta.Target.FieldOrProperty.Value != value) {
          string artikelID = GetArtikelID(meta.This);

          if (!string.IsNullOrEmpty(artikelID)) {
            IArtikelDomainController artikelDomainController = DomainControllerFactory.Instance.CreateDomainController<IArtikelDomainController>();
            ArtikelVO artikel = artikelDomainController.GetArtikelVOByID(artikelID);
            if (artikel != null) {

              value = Rounder.Round((double)value, artikel.RundungsfaktorMengen, RounderType.Standard);
            }
          }

          meta.Target.FieldOrProperty.Value = value;
          if (meta.This is IPPNotifyPropertyChanged notifyPropertyChanged) {
            notifyPropertyChanged.OnPropertyChanged(meta.Target.FieldOrProperty.Name);
          }
        }
      }
    }

    #endregion Public Methods

    #region Private Methods

    [IntroduceDependency]
    private string GetArtikelID(object instance) {
      Type typ = instance.GetType();
      PropertyInfo propInfo = typ.GetProperty(_artikelPropertyName);

      if (propInfo == null) {
        throw new Exception($"Die Property '{_artikelPropertyName}' wurde für das Object vom Typ '{typ}' nicht gefunden");
      }

      return propInfo.GetValue(instance, null).ToText();
    }

    #endregion Private Methods

  }
}

Usage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Printplus.Druck.Common.Aspects;

namespace Printplus.Druck.Materialeinkauf.Entity {

  public class EditMaterialbedarfVO: NotifyPropertyChangedBase {

    #region Public Properties

    [ArtikelRounder("BedarfsmaterialID")]
    public double SollMenge { get; set; }

    [ArtikelRounder("BereitstellungsmaterialID")]
    public double Menge { get; set; }

    [ArtikelRounder("BereitstellungsmaterialID")]
    public double KorrekturMenge { get; set; }

    [ArtikelRounder("BereitstellungsmaterialID")]
    public double VerbrauchteMenge { get; set; }

    [ArtikelRounder("BereitstellungsmaterialID")]
    public double AusgleichsMenge { get; set; }

...

    #endregion Public Properties

  }
}
svick commented 1 month ago

As documented, the [IntroduceDependency] attribute only works on fields and autoproperties, so you can't have it on your GetArtikelID method. It's not clear to me what you expect that to do, so I can't suggest what you should do instead.

I am going to improve the code, so that doing this produces a clear error message instead of the confusing exception you got.

wabluk commented 1 month ago

The problem was a missing Reference to a dll which was not needen with PostSharp. Thanks!

svick commented 1 month ago

I'm glad that you resolved your issue.