2010-07-20 2 views
22

Скажем, у меня есть метод:Есть ли способ получить массив аргументов, переданных методу?

public void SomeMethod(String p1, String p2, int p3) 
{ 

#if DEBUG 
    object[] args = GetArguments(); 
    LogParamaters(args); 
#endif 

    // Do Normal stuff in the method 
} 

Есть ли способ, чтобы получить массив аргументов, передаваемых в метод, так что они могут быть зарегистрированы?

У меня есть большое количество методов и хочу избежать вручную передачи аргументов по имени к регистратору, так как человеческая ошибка будет неизбежно ползти в

Я предполагаю, что это будет включать в себя отражение в том или иной форме. - которые в порядке, поскольку он будет использоваться только для целей отладки.

Update

Немного больше информации:

Я не могу изменить метод подписи SomeMethod, поскольку она подвергается воздействию как WebMethod и должен повторить унаследованной системы она выдает себя.

Унаследованная система уже регистрирует аргументы, которые передаются. Для начала с новой реализацией будет завершена устаревшая система, поэтому я ищу для регистрации параметров, входящих в версию C#, чтобы я мог проверить правильность параметры передаются в правильном порядке.

Я просто ищу, чтобы регистрировать значения и порядок аргументов, а не их имена.

+0

Какие сведения о параметрах хранятся в журнале? тип, имя, значение? – devnull

+0

это означает, что вы действительно говорите об _arguments_, а не _parameters_. [(См., Например, здесь для объяснения различий.)] (Http://msdn.microsoft.com/en-us/library/9kewt1b3%28VS.80%29.aspx) – stakx

+0

@stax, да, это различие имеет смысл , Я ищу значения аргументов, переданные в метод. –

ответ

0

Вот что я придумал как решение:

PostSharp или другой АОП решение не было на самом деле практичны в этой ситуации, поэтому, к сожалению, мне пришлось отказаться от этой идеи.

Похоже, что при использовании отражения можно указывать имена и типы параметров, единственный способ получить доступ к значениям времени выполнения - при подключенном отладчике.

Смотрите здесь для получения дополнительной информации:

StackOverflow

microsoft.public.dotnet.framework

Так что все-таки оставил меня с проблемой ~ 50 методов, необходимых это протоколирование добавление вручную.

Отражение на помощь ...

public String GetMethodParameterArray() 
    { 
     var output = new StringBuilder(); 
     output.AppendLine(); 

     Type t = typeof(API); 
     foreach (var mi in t.GetMethods()) 
     { 
       var argsLine = new StringBuilder(); 
       bool isFirst = true; 
       argsLine.Append("object[] args = {"); 
       var args = mi.GetParameters(); 

       foreach (var pi in args) 
       { 
        if (isFirst) 
        { 
         isFirst = false; 
        } 
        else 
        { 
         argsLine.Append(", "); 
        } 
        argsLine.AppendFormat("{0}", pi.Name); 
       } 
       argsLine.AppendLine("};"); //close object[] initialiser 

       output.AppendLine(argsLine.ToString()); 
       output.AppendFormat("Log(\"{0}\",args);", mi.Name); 
       output.AppendLine(); 
       output.AppendLine(); 
      } 
     return output.ToString(); 
    } 

Этот фрагмент кода перебирает методов на классе и выводит объект [] массив инициализируется с аргументами, переданными в метод и журнал вызовов, содержащий аргументы и имя метода.

Пример вывод:

object[] args = {username, password, name, startDate, endDate, cost}; 
Log("GetAwesomeData",args); 

Этот блок может быть вставлен в верхнюю части методы для достижения требуемого эффекта.

Это более ручной, чем мне хотелось бы, но это намного лучше, чем набирать параметры вручную и гораздо меньше подверженных ошибкам.

0

Там какая-то функциональность с динамической системой типов, которые могут это сделать, но тогда ваш класс должен наследовать от динамических базовых классов

+0

Вы даже прочитали вопрос? Он хочет записать все параметры, входящие в функцию, и хотел бы получить доступ к этим данным. – Oded

1

Ну, если вы просто хотите, чтобы передать значения, вы можете обмануть и определим массив объектов:

public static void LogParameters(params object[] vals) 
{ 

} 

Это приведет к боксу по типам значений, но также не даст вам никаких имен параметров.

Скажем, у меня есть метод:

public void SomeMethod(String p1, String p2, int p3) 
{ 

#if DEBUG 
    LogParamaters(p1, p2, p3); 
#endif 

    // Do Normal stuff in the method 
} 

Update:, к сожалению, отражение не будет делать все это для вас автоматически. Вам нужно будет предоставить значение, но вы можете использовать отражение, чтобы обеспечить имена Param/типов:

How can you get the names of method parameters?

Так что метод сиг изменится на что-то вроде:

public static void LogParameters(string[] methodNames, params object[] vals) 
{ } 

Тогда вы можете применять/предполагать, что каждый индекс в каждой коллекции соответствует, так что methodNames[0] имеет значение vals[0].

+0

Если возможно, я пытаюсь избежать записи имен параметров в вызове LogParameters, поэтому для чего-то вроде: LogParamaters (GetMethodParams()); где GetMethodParams() вернет массив paramaters. Я не слишком беспокоюсь о боксе над головой. –

+0

Я изменил свой ответ, но, как утверждают другие, существуют рамки для добавления необходимого кода в качестве шага компилятора - это означает, что вам не нужно много писать вручную. –

+0

Конечно, единственный недостаток с PostSharp заключается в том, что он не бесплатный, и вам по-прежнему нужно отредактировать код для размещения атрибута. –

7

Если вы используете Postsharp, вы можете просто добавить атрибут к методу, который хотите записать. Внутри этого атрибута вы можете записать код ведения журнала, а также предоставить необходимые аргументы. Это известно как проблемы перекрестной резки и AOP (ориентированное на ориентирование программирование)

+0

+1. Я собирался написать что-то о том, чтобы автоматически переписать вывод CIL компилятором для добавления журнала, но просто использовать установленный продукт, вероятно, будет проще. – stakx

+0

Кроме того, выполнение вышеописанного действия является простым и простым в использовании. – aqwert

1

Ну params Помогите с вызовом журнала, но не поможет существующим сигнатурам метода. Регистрация с использованием AOP framework может быть более продуктивным подходом?

4

Я не уверен, что API для доступа к стеку вызовов предоставляет средство для получения списка аргументов.

Однако существуют способы инъекции IL для перехвата вызовов метода и выполнения пользовательского кода.

Библиотека, которую я часто использую, - PostSharp от Gael Fraiteur, включает приложение, которое запускает postbuild и внедряет IL в ваши выходные сборки в зависимости от используемых вами аспектов. Есть атрибуты, с помощью которых вы можете украшать сборки, типы или отдельные методы. Например:

[Serializable] 
public sealed class LoggingAttribute : OnMethodBoundaryAspect 
{ 
    public override void OnEntry(MethodExecutionArgs eventArgs) 
    { 
     Console.WriteLine("Entering {0} {1} {2}", 
          eventArgs.Method.ReflectedType.Name, 
          eventArgs.Method, 
          string.Join(", ", eventArgs.Arguments.ToArray())); 

     eventArgs.MethodExecutionTag = DateTime.Now.Ticks; 
    } 

    public override void OnExit(MethodExecutionArgs eventArgs) 
    { 
     long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag; 
     TimeSpan ts = TimeSpan.FromTicks(elapsedTicks); 

     Console.WriteLine("Leaving {0} {1} after {2}ms", 
          eventArgs.Method.ReflectedType.Name, 
          eventArgs.Method, 
          ts.TotalMilliseconds); 
    } 
} 

После этого вы можете просто украсить метод, который вы хотите с этим атрибутом:

[Logging] 
public void SomeMethod(String p1, String p2, int p3) 
{ 
    //.. 
} 
+0

('System.Diagnostics.StackTrace' /' System.Diagnostics.StackFrame', по-видимому, предоставляют только исходное имя файла и номер строки и т. Д., А не фактические аргументы.) – stakx

0

может не работать в некоторых сценариях, но должны вы начали :)

class Program 
{ 
    static void Main(string[] args) 
    { 
     M1("test"); 
     M2("test", "test2"); 
     M3("test", "test2", 1); 

     Console.ReadKey(); 
    } 

    static void M1(string p1) 
    { 
     Log(MethodBase.GetCurrentMethod()); 
    } 

    static void M2(string p1, string p2) 
    { 
     Log(MethodBase.GetCurrentMethod()); 
    } 

    static void M3(string p1, string p2, int p3) 
    { 
     Log(MethodBase.GetCurrentMethod()); 
    } 

    static void Log(MethodBase method) 
    { 
     Console.WriteLine("Method: {0}", method.Name); 
     foreach (ParameterInfo param in method.GetParameters()) 
     { 
      Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name); 
     } 
    } 
} 
+0

после исправления для добавления отсутствующего пространства имен System.Reflection it note it не указывайте значения. –

0

До тех пор, пока вы знаете, какие типы ожидают, что вы сможете зарегистрировать их в базе данных SQL. Напишите метод, который выполняет проверку типа, а затем заполняет соответствующий столбец БД значением параметра (аргумента). Если у вас есть собственный тип, вы можете использовать имя типа и сохранить его как строку в своем специальном столбце.

-Edit

Кроме того, с помощью метода MethodBase.Name расширения, вы можете связать свои параметры с помощью метода, который принял их в качестве аргументов, как указано в другом посте ниже. Быть удобным способом отслеживания всех используемых методов и с какими аргументами и какого типа.

Это даже смутно хорошая идея? :)

Смежные вопросы