2016-08-03 4 views
2

В настоящее время мы работаем над решением регистрации и внедрили вызов метода расширения «Журнал». При записи в файл журнала нам идеально хотелось бы написать исходное имя переменной (а не имя переменной, используемое в методе расширения).Получение исходного имени переменной из метода расширения

То, что мы в настоящее время приходится делать для этого:

public void DoSomeWork() 
{ 
    String testString = "Hey look I'm a string!"; 
    testString.Log("testString value"); 
} 

С помощью метода РАСШИРЕНИЯ:

public static String Log(this String valueToStore, String name) 
{ 
    // The logging code which uses the 'name' parameter 
} 

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

public void DoSomeWork() 
{ 
    String testString = "Hey look I'm a string!"; 
    testString.Log(); 
} 

С помощью метода расширения:

public static String Log(this String valueToStore) 
{ 
    // The logging code which is able to retrieve the 
    // value 'testString' from the 'valueToStore' value 
} 

Является ли это вообще возможно с помощью отражения? Я знаю параметр nameof, но это возвращает строку «valueToStore» при использовании в методе расширения.

+0

Я не думаю, что это возможно. Эта информация теряется на этом этапе выполнения (переменная не является даже свойством или полем, на которое вы могли бы подумать). Вы можете подобрать кадр стека и изучить метод вызова для его строковых переменных, но это не поможет. btw: что бы вы ожидали от «hello world» .Log() '? –

+0

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

+0

Нет, методы расширения - это просто синтаксический сахар. 'testString.Log()' в вашем примере не отличается от 'YourExtensionClass.Log (testString)'. –

ответ

2

Вы можете использовать Expression для достижения этой цели, но производительность мудрый не может быть лучшим вариантом:

public static void Log<T>(Expression<Func<T>> expr) 
{ 
    var memberExpr = expr.Body as MemberExpression; 

    if (memberExpr == null) 
     return; 

    var varName = memberExpr.Member.Name; 
    var varData = expr.Compile()(); 

    // actual logging 
    ... 
} 

Использование:

var test = "Foo"; 
Log(() => test); 

В качестве альтернативы, если вы используете C# 6.0 , он может получить немного лучше с помощью nameof оператора:

test.Log(nameof(test)); 

Лучшим решением будет использование возможностей компилятора (в частности, компилятор «Roslyn») и предоставление имени участника во время компиляции.

+0

Как бы использование было реализовано как метод расширения, или это решение будет отходить от этого? –

+0

@ChrisWright, вы можете расширить его как метод расширения, но это будет выглядеть довольно неудобно: 'test.Log (() => test)'. Я могу изменить ответ, чтобы отразить это, если хотите. – haim770

+0

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

0

Не совсем ответ, скорее указатель, но вы можете попробовать что-то сделать с вашим приложением, которое вы используете (например, визуальная студия), вместо того, чтобы делать это в коде. Я имею в виду, что он переписывает все, что выглядит как [variable].Log();: [variable].Log([variable])

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

0

Ну, короткий ответ - нет. Имена переменных не будут сохраняться после компиляции в неизмененной форме. Эта информация должна быть как-то сохранена (например, с использованием nameof()). Кроме того, имя переменной может не существовать ("test".GetVarName()).

Длинный ответ: да, возможно, но это одна из самых смешных вещей, которые я создал в своей жизни:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Reflection; 

namespace Test1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var myVarName = "test"; 
      myVarName.Test(); 
      Console.ReadKey(); 
     } 
    } 

    static class Extensions 
    { 
     public static void Test(this string str, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", 
     [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", 
     [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) 
     { 
      var relevantLine = File.ReadAllLines(sourceFilePath)[sourceLineNumber-1]; 
      var currMethodName = MethodInfo.GetCurrentMethod().Name; 
      var callIndex = relevantLine.IndexOf(currMethodName + "()"); 
      var sb = new Stack<char>(); 
      for (var i = callIndex - 2; i >= 0; --i) 
      { 
       if (char.IsLetterOrDigit(relevantLine[i])) 
        sb.Push(relevantLine[i]); 

      } 
      Console.WriteLine(new string(sb.ToArray())); 
     } 
    } 
} 
Смежные вопросы