it-swarm-ko.tech

함수에 전달 된 변수 이름 찾기

다음 예를 사용하여 질문을 설명하겠습니다.

public string ExampleFunction(string Variable) {
    return something;
}

string WhatIsMyName = "Hello World"';
string Hello = ExampleFunction(WhatIsMyName);

변수 "WhatIsMyName"을 예제 함수에 전달하면 원래 변수 이름의 문자열을 얻을 수 있기를 원합니다. 아마도 다음과 같습니다.

Variable.OriginalName.ToString()

이것을 할 수있는 방법이 있습니까?

56
GateKiller

원하는 것은 직접 가능하지 않지만 C # 3.0에서 표현식을 사용할 수 있습니다.

public void ExampleFunction(Expression<Func<string, string>> f) {
    Console.WriteLine((f.Body as MemberExpression).Member.Name);
}

ExampleFunction(x => WhatIsMyName);

이것은 지정되지 않은 동작에 의존하며 Microsoft의 현재 C # 및 VB 컴파일러, and에서는 Mono의 C # 컴파일러에서 작동하지만 이것이 보장되지는 않는다는 보장은 없습니다. 향후 버전에서 작동을 중지하십시오.

57
Konrad Rudolph

이것은 정확히 원하는 방식으로 불가능합니다. C # 6.0 코드를 개선하고 단순화하는 데 도움이되는 연산자 이름을 소개합니다. 연산자의 이름은 전달 된 변수의 이름을 확인합니다.

귀하의 경우 사용법은 다음과 같습니다.

public string ExampleFunction(string variableName) {
      //Construct your log statement using c# 6.0 string interpolation
       return $"Error occurred in {variableName}";
}

string WhatIsMyName = "Hello World"';
string Hello = ExampleFunction(nameof(WhatIsMyName));

주요 이점은 컴파일 타임에 수행된다는 것입니다.

표현식의 이름은 상수입니다. 모든 경우에 nameof (...)는 컴파일 타임에 평가되어 문자열을 생성합니다. 인수는 런타임시 평가되지 않으며 도달 할 수없는 코드로 간주됩니다 (단, "연결할 수없는 코드"경고는 발생하지 않습니다).

더 많은 정보를 찾을 수 있습니다 여기

C 3.0 이상의 이전 버전
Nawfals 답변을 바탕으로

GetParameterName2(new { variable });

//Hack to assure compiler warning is generated specifying this method calling conventions
[Obsolete("Note you must use a single parametered AnonymousType When Calling this method")]
public static string GetParameterName<T>(T item) where T : class
{
    if (item == null)
        return string.Empty;

    return typeof(T).GetProperties()[0].Name;
}
31
johnny 5
static void Main(string[] args)
{
  Console.WriteLine("Name is '{0}'", GetName(new {args}));
  Console.ReadLine();
}

static string GetName<T>(T item) where T : class
{
  var properties = typeof(T).GetProperties();
  Enforce.That(properties.Length == 1);
  return properties[0].Name;
}

자세한 내용은 이 블로그 게시물 에 있습니다.

18
Rinat Abdullin

세 가지 방법 :

1) 전혀 반영되지 않은 것 :

GetParameterName1(new { variable });

public static string GetParameterName1<T>(T item) where T : class
{
    if (item == null)
        return string.Empty;

    return item.ToString().TrimStart('{').TrimEnd('}').Split('=')[0].Trim();
}

2) 반사를 사용하지만 다른 두 가지보다 빠릅니다.

GetParameterName2(new { variable });

public static string GetParameterName2<T>(T item) where T : class
{
    if (item == null)
        return string.Empty;

    return typeof(T).GetProperties()[0].Name;
}

3) 가장 느린 것은 사용하지 마십시오.

GetParameterName3(() => variable);

public static string GetParameterName3<T>(Expression<Func<T>> expr)
{
    if (expr == null)
        return string.Empty;

    return ((MemberExpression)expr.Body).Member.Name;
}

콤보 매개 변수 이름과 값을 얻으려면 이러한 메소드를 확장 할 수 있습니다. 물론 다른 인수로 매개 변수를 별도로 전달하면 쉽게 가치를 얻을 수 있지만 이는 중요하지 않습니다. 대신 :

1)

public static string GetParameterInfo1<T>(T item) where T : class
{
    if (item == null)
        return string.Empty;

    var param = item.ToString().TrimStart('{').TrimEnd('}').Split('=');
    return "Parameter: '" + param[0].Trim() +
           "' = " + param[1].Trim();
}

2)

public static string GetParameterInfo2<T>(T item) where T : class
{
    if (item == null)
        return string.Empty;

    var param = typeof(T).GetProperties()[0];
    return "Parameter: '" + param.Name +
           "' = " + param.GetValue(item, null);
}

삼)

public static string GetParameterInfo3<T>(Expression<Func<T>> expr)
{
    if (expr == null)
        return string.Empty;

    var param = (MemberExpression)expr.Body;
    return "Parameter: '" + param.Member.Name +
           "' = " + ((FieldInfo)param.Member).GetValue(((ConstantExpression)param.Expression).Value);
}

1과 2는 현재 속도가 비슷하고 3은 다시 느리다.

13
nawfal

아니요, 그러나 이와 같이 매우 복잡한 작업을 수행 할 때마다 솔루션을 다시 생각할 수 있습니다. 코드는 작성하는 것보다 읽기 쉬워야합니다.

4
Nate Kohari

예! 가능합니다. 나는 이것에 대한 해결책을 오랫동안 찾고 있었고 마침내 그것을 해결하는 해킹을 생각해 냈습니다 (약간 불쾌합니다). 나는 이것을 프로그램의 일부로 사용하는 것을 권장하지 않으며 디버그 모드에서만 작동한다고 생각합니다. 나를 위해 이것은 콘솔 클래스에서 디버깅 도구로만 사용하므로 중요하지 않습니다.

int testVar = 1;
bool testBoolVar = True;
myConsole.Writeline(testVar);
myConsole.Writeline(testBoolVar);

콘솔의 출력은 다음과 같습니다.

testVar: 1
testBoolVar: True

여기에 내가하는 기능이 있습니다 (콘솔 클래스의 줄 바꿈 코드는 포함되지 않음).

    public Dictionary<string, string> nameOfAlreadyAcessed = new Dictionary<string, string>();
    public string nameOf(object obj, int level = 1)
    {
        StackFrame stackFrame = new StackTrace(true).GetFrame(level);
        string fileName = stackFrame.GetFileName();
        int lineNumber = stackFrame.GetFileLineNumber();
        string uniqueId = fileName + lineNumber;
        if (nameOfAlreadyAcessed.ContainsKey(uniqueId))
            return nameOfAlreadyAcessed[uniqueId];
        else
        {
            System.IO.StreamReader file = new System.IO.StreamReader(fileName);
            for (int i = 0; i < lineNumber - 1; i++)
                file.ReadLine();
            string varName = file.ReadLine().Split(new char[] { '(', ')' })[1];
            nameOfAlreadyAcessed.Add(uniqueId, varName);
            return varName;
        }
    }
4
blooop

System.Environment.StackTrace는 현재 호출 스택을 포함하는 문자열을 제공합니다. 각 호출에 대한 변수 이름이 포함 된 정보를 얻기 위해 구문 분석 할 수 있습니다.

2
kevin42

이 유틸리티 클래스를 사용해보십시오.

public static class Utility
{
    public static Tuple<string, TSource> GetNameAndValue<TSource>(Expression<Func<TSource>> sourceExpression)
    {
        Tuple<String, TSource> result = null;
        Type type = typeof (TSource);
        Func<MemberExpression, Tuple<String, TSource>> process = delegate(MemberExpression memberExpression)
                                                                    {
                                                                        ConstantExpression constantExpression = (ConstantExpression)memberExpression.Expression;
                                                                        var name = memberExpression.Member.Name;
                                                                        var value = ((FieldInfo)memberExpression.Member).GetValue(constantExpression.Value);
                                                                        return new Tuple<string, TSource>(name, (TSource) value);
                                                                    };

        Expression exception = sourceExpression.Body;
        if (exception is MemberExpression)
        {
            result = process((MemberExpression)sourceExpression.Body);
        }
        else if (exception is UnaryExpression)
        {
            UnaryExpression unaryExpression = (UnaryExpression)sourceExpression.Body;
            result = process((MemberExpression)unaryExpression.Operand);
        }
        else
        {
            throw new Exception("Expression type unknown.");
        }

        return result;
    }


}

그리고 그것을 좋아하는 사용자

    /*ToDo : Test Result*/
    static void Main(string[] args)
    {
        /*Test : primivit types*/
        long maxNumber = 123123;
        Tuple<string, long> longVariable = Utility.GetNameAndValue(() => maxNumber);
        string longVariableName = longVariable.Item1;
        long longVariableValue = longVariable.Item2;

        /*Test : user define types*/
        Person aPerson = new Person() { Id = "123", Name = "Roy" };
        Tuple<string, Person> personVariable = Utility.GetNameAndValue(() => aPerson);
        string personVariableName = personVariable.Item1;
        Person personVariableValue = personVariable.Item2;

        /*Test : anonymous types*/
        var ann = new { Id = "123", Name = "Roy" };
        var annVariable = Utility.GetNameAndValue(() => ann);
        string annVariableName = annVariable.Item1;
        var annVariableValue = annVariable.Item2;

        /*Test : Enum tyoes*/
        Active isActive = Active.Yes;
        Tuple<string, Active> isActiveVariable = Utility.GetNameAndValue(() => isActive);
        string isActiveVariableName = isActiveVariable.Item1;
        Active isActiveVariableValue = isActiveVariable.Item2;
    }
2
Dipon Roy

이 작업을 수행

var myVariable = 123;
myVariable.Named(() => myVariable);
var name = myVariable.Name();
// use name how you like

또는 손으로 코드에서 명명

var myVariable = 123.Named("my variable");
var name = myVariable.Name();

이 클래스를 사용하여

public static class ObjectInstanceExtensions
{
    private static Dictionary<object, string> namedInstances = new Dictionary<object, string>();

    public static void Named<T>(this T instance, Expression<Func<T>> expressionContainingOnlyYourInstance)
    {
        var name = ((MemberExpression)expressionContainingOnlyYourInstance.Body).Member.Name;
        instance.Named(name);            
    }

    public static T Named<T>(this T instance, string named)
    {
        if (namedInstances.ContainsKey(instance)) namedInstances[instance] = named;
        else namedInstances.Add(instance, named);
        return instance;
    }        

    public static string Name<T>(this T instance)
    {
        if (namedInstances.ContainsKey(instance)) return namedInstances[instance];
        throw new NotImplementedException("object has not been named");
    }        
}

코드 테스트를 거쳐 가장 우아합니다.

1
kernowcode

GateKiller, 해결 방법에 어떤 문제가 있습니까? 함수를 사용하기 위해 사소하게 함수를 다시 작성할 수 있습니다 (즉석에서 함수를 향상시키기 위해 자유를 얻었습니다).

static string sMessages(Expression<Func<List<string>>> aMessages) {
    var messages = aMessages.Compile()();

    if (messages.Count == 0) {
        return "";
    }

    StringBuilder ret = new StringBuilder();
    string sType = ((MemberExpression)aMessages.Body).Member.Name;

    ret.AppendFormat("<p class=\"{0}\">", sType);
    foreach (string msg in messages) {
        ret.Append(msg);
        ret.Append("<br />");
    }
    ret.Append("</p>");
    return ret.ToString();
}

다음과 같이 호출하십시오.

var errors = new List<string>() { "Hi", "foo" };
var ret = sMessages(() => errors);
0
Konrad Rudolph

모든 답변에 감사드립니다. 나는 내가 지금하고있는 일과 함께 가야한다고 생각합니다.

왜 내가 위의 질문을했는지 알고 싶은 사람들을 위해. 다음과 같은 기능이 있습니다.

string sMessages(ArrayList aMessages, String sType) {
    string sReturn = String.Empty;
    if (aMessages.Count > 0) {
        sReturn += "<p class=\"" + sType + "\">";
        for (int i = 0; i < aMessages.Count; i++) {
            sReturn += aMessages[i] + "<br />";
        }
        sReturn += "</p>";
    }
    return sReturn;
}

오류 메시지 배열과 CSS 클래스를 보내면 웹 페이지의 문자열로 반환됩니다.

이 함수를 호출 할 때마다 sType을 정의해야합니다. 다음과 같은 것 :

output += sMessages(aErrors, "errors");

보시다시피 내 변수는 aErrors이고 CSS 클래스는 errors입니다. 나는 내 감기가 내가 보낸 변수 이름을 기반으로 어떤 클래스를 사용할지 알아낼 수 있기를 바랐다.

다시 한 번, 모든 답변에 감사드립니다.

0
GateKiller

아니요. 문자열 변수에 대한 참조는 함수에 전달됩니다. 포함 된 고유 메타 데이터는 없습니다. 리플렉션조차도 여기에서 숲을 벗어날 수는 없습니다. 단일 참조 유형에서 뒤로 작업해도 필요한 정보를 얻을 수있는 충분한 정보를 얻지 못합니다.

이 보드의 드로잉 보드로 돌아가는 것이 좋습니다!

rp

0
rp.

리플렉션을 사용하여 객체의 모든 속성을 가져 와서 루프하는 것보다 속성의 이름이 전달 된 매개 변수와 일치하는 속성의 값을 얻을 수 있습니다.

0
Adam Vigh