PostSharp и Delegate
От: alexsoff Россия  
Дата: 09.10.09 13:30
Оценка:
Здравствуйте.
Начал изучать АОП, создаю UI save thread аспект:

public class FormsThreadAttribute : OnMethodInvocationAspect{ 
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
    Form f = (Form)eventArgs.Delegate.Target;
    if (f.InvokeRequired)
      f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray());   
 else      eventArgs.Proceed();  
}
}


Но свойство Delegate у eventArgs отмечено как Obsolete, есть другой способ?
Спасибо.
Re: PostSharp и Delegate
От: _FRED_ Черногория
Дата: 09.10.09 13:51
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Начал изучать АОП, создаю UI save thread аспект:

A>public class FormsThreadAttribute : OnMethodInvocationAspect{ 
…

A>Но свойство Delegate у eventArgs отмечено как Obsolete, есть другой способ?

Внимательнее читайте сообщения компилятора и прочую доступную вам информацию:
[ObsoleteAttribute("Use the Method and Instance properties instead.")]
public Delegate Delegate { get; }

здесь
Help will always be given at Hogwarts to those who ask for it.
Re[2]: PostSharp и Delegate
От: alexsoff Россия  
Дата: 09.10.09 14:08
Оценка:
Здравствуйте, _FRED_, Вы писали:
_FR>[/c#]
_FR>здесь
Это я читал, только вот что передавать
form.Invoke(Delegate.CreateDelegate(typeof(?????), eventArgs.Method), eventArgs.GetArgumentArray());

Где взять тип для создаваемого делегата?
Re[3]: PostSharp и Delegate
От: _FRED_ Черногория
Дата: 09.10.09 15:07
Оценка:
Здравствуйте, alexsoff, Вы писали:

[/c#]
_FR>>здесь
A>Это я читал,

Тогда сразу надо было сказать об этом и точно спросить то, что интересует.

A>только вот что передавать

A>form.Invoke(Delegate.CreateDelegate(typeof(?????), eventArgs.Method), eventArgs.GetArgumentArray());

A>Где взять тип для создаваемого делегата?

Если я правильно понимаю, аспект срабатывает при вызове метода. Например, метод такой вот:
public void Test() { }

Какой должен быть делегат:
public delegate void Action();

или
public delegate void CrossAppDomainDelegate();

а может
public delegate void ThreadStart();



Видимо, и заобсолители свойство Delegate из-за его неоднозначности.

Для большинства случаев подойдёт что-то такое (поиск подходящего делегата из Action-ов и Func-ов, до четырёх параметров, без out\ref-параметров):
using System;
using System.Diagnostics;
using System.Reflection;

public static class DelegateHelper
{
  #region Fields

  private static readonly Type[] Actions = new[]
  {
    typeof(Action),
    typeof(Action<>),
    typeof(Action<,>),
    typeof(Action<,,>),
    typeof(Action<,,,>),
  };

  private static readonly Type[] Funcs = new[]
  {
    typeof(Func<>),
    typeof(Func<,>),
    typeof(Func<,,>),
    typeof(Func<,,,>),
    typeof(Func<,,,,>),
  };

  #endregion Fields

  #region Constructor(s)

  static DelegateHelper() {
    Debug.Assert(Actions.Length == Funcs.Length, "Actions.Length == Funcs.Length");
  }

  #endregion Constructor(s)

  #region Methods

  public static Type GetDelegateType(MethodInfo info) {
    if(info == null) {
      throw new ArgumentNullException("info");
    }//if

    var action = info.ReturnType == typeof(void);
    var types = action ? Actions : Funcs;
    Debug.Assert(types != null, "types != null");

    var parameters = Array.ConvertAll(info.GetParameters(), parameter => parameter.ParameterType);
    if(parameters.Length > types.Length) {
      throw new NotSupportedException();
    }//if

    var type = types[parameters.Length];
    if(!action) {
      var copy = new Type[parameters.Length + 1];
      parameters.CopyTo(copy, 0);
      parameters = copy;
      parameters[parameters.Length - 1] = info.ReturnType;
    }//if
    return type.IsGenericTypeDefinition ? type.MakeGenericType(parameters) : type;
  }

  #endregion Methods
}

static class Program
{
  static void Main() {
    Converter<string, Type> converter = name => DelegateHelper.GetDelegateType(typeof(Program).GetMethod(name));
    var t1 = converter("A0");
    var t2 = converter("A1");
    var t3 = converter("A2");
    var t4 = converter("A3");
    var t5 = converter("A4");
    var t6 = converter("F0");
    var t7 = converter("F1");
    var t8 = converter("F2");
    var t9 = converter("F3");
    var tA = converter("F4");
  }

  public static void A0() { }
  public static void A1(int x) { }
  public static void A2(int x, int y) { }
  public static void A3(int x, int y, int z) { }
  public static void A4(int x, int y, int z, int w) { }

  public static int F0() { return 0; }
  public static int F1(int x) { return 0; }
  public static int F2(int x, int y) { return 0; }
  public static int F3(int x, int y, int z) { return 0; }
  public static int F4(int x, int y, int z, int w) { return 0; }
}
Help will always be given at Hogwarts to those who ask for it.
Re[3]: PostSharp и Delegate
От: Lloyd Россия  
Дата: 09.10.09 15:13
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Где взять тип для создаваемого делегата?


Посмотрите пример со стартовой страницы сайта postsharp-а. Там как раз то, что вы пытаетесь написать.
Re[4]: PostSharp и Delegate
От: alexsoff Россия  
Дата: 09.10.09 16:15
Оценка:
Здравствуйте, _FRED_, Вы писали:
[]
Спасибо за хелпер, но к сожалению, он не до конца универсален, попробую покопать еще...
Re[4]: PostSharp и Delegate
От: alexsoff Россия  
Дата: 09.10.09 16:23
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Посмотрите пример со стартовой страницы сайта postsharp-а. Там как раз то, что вы пытаетесь написать.



public class GuiThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    DispatcherObject dispatcherObject = (DispatcherObject)eventArgs.Delegate.Target;
    if (dispatcherObject.CheckAccess())
      eventArgs.Proceed(); 
    else
      dispatcherObject.Dispatcher.Invoke( DispatcherPriority.Normal, 
                                          new Action(() => eventArgs.Proceed()));
  }
}

Там они сами используют obsolete свойство.
Re: PostSharp и Delegate
От: alexsoff Россия  
Дата: 09.10.09 16:49
Оценка:
Здравствуйте, alexsoff, Вы писали:

A>Но свойство Delegate у eventArgs отмечено как Obsolete, есть другой способ?

Решение оказалось до банальности простым:
[Serializable]
    public class UIThreadInvokerAttribute : OnMethodInvocationAspect
    {
        #region Overrides of OnMethodInvocationAspect

        /// <summary>
        ///             Method called instead of the intercepted method.
        /// </summary>
        /// <param name="eventArgs">Event arguments specifying which method
        /// is being executed and which are its arguments. The implementation
        /// should set the return value and ouput arguments.</param>
        public override void OnInvocation( MethodInvocationEventArgs eventArgs )
        {
            Form form = eventArgs.Instance as Form;

            if ( form!= null ) {

                if ( form.InvokeRequired ) {
                    form.Invoke( new ThreadStart( () => eventArgs.Proceed() ) );
                } else {
                    eventArgs.Proceed();
                }

            }
        }

        #endregion
    }

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.