I suggest you ...

Compliable strings

If you're writing a tracing and logging component you may well want to pass the current method name to your logging component. Rather than hard code it (then forget to change it when you change the method name) you can use reflection and the MethodBase class to retrieve the name:
System.Reflection.MethodBase currentMethod = System.Reflection.MethodBase.GetCurrentMethod();
System.Diagnostics.Debug.WriteLine(currentMethod.Name);
System.Diagnostics.Debug.WriteLine(currentMethod.DeclaringType.Name);
System.Diagnostics.Debug.WriteLine(currentMethod.DeclaringType.Namespace);

In C # 4.5 you can use attributes System.Runtime.CompilerServices.CallerMemberNameAttribute, System.Runtime.CompilerServices.CallerFilePathAttribute and System.Runtime.CompilerServices.CallerLineNumberAttribute for such purposes.

Frequent use of reflection dramatically reduces performance. Using special attributes is a contentious issue. Because attributes inherently are declarative. They obviously do not provide full support for the aspect programming. Thus, we can conclude that C# developers have created next hack for improving programmability.

At the moment, there is another solution of such a problem. You can use expression trees to improve the code readability. This is a very good approach, especially for refactoring, but it may reduce performance.

class Program {
public static Int32 Counter { get { return _counter; }
set {
if (value < 0) throw new ArgumentNullException(Name.ToString(() => Counter));
_counter = value;
}
}
private static Int32 _counter;
private static void DisplayCounter() { Console.WriteLine("{0}={1}", Name.ToString(() => _counter), _counter); }
static void Main(string[] args) {
Counter = 100;
DisplayCounter();
}
}

using System;
using System.Linq.Expressions;
public static class Name {
public static String ToString(Expression<Action> memberExpression)
{
return _ToString(memberExpression);
}

public static String ToString<T>(Expression<Func<T, Object>> memberExpression)
{
return _ToString(memberExpression);
}

public static String ToString<T>(Expression<Action<T>> memberExpression)
{
return _ToString(memberExpression);
}

public static String ToString(Expression<Func<Object>> memberExpression)
{
return _ToString(memberExpression);
}

private static String _ToString(Expression memberExpression)
{
if (memberExpression == null)
throw new ArgumentNullException("memberExpression");

try
{
var lambda = (LambdaExpression)memberExpression;
var subexpr = lambda.Body;

String name = null;
for (; ; )
{
switch (subexpr.NodeType)
{
case ExpressionType.Call:
name = ((MethodCallExpression)subexpr).Method.Name;
break;

case ExpressionType.Convert:
subexpr = ((UnaryExpression)subexpr).Operand;
continue;

case ExpressionType.MemberAccess:
name = ((MemberExpression)subexpr).Member.Name;
break;

default:
throw new InvalidOperationException();
}
break;
}
return name ?? memberExpression.ToString();
}
catch
{
return memberExpression.ToString();
}
}
}

What if it would be possible to write code that the compiler checked and converted at compile time to a string:

`Counter` => "Counter"
`Program.Counter` => "Program.Counter"
`_counter` => "_counter"
`Counter` => "Counter"
`Display()` => "Display"
`String.Equals` => "String.Equals"
`String.Equals(String, String)` => "String.Equals"

If during compilation process code item mapping failed, the compiler generates an error.

This feature would allow to write faster and better code. Also should mention the opportunities for effective use refactoring. Likewise, the DLR can be extended. It may be safer and more comfortable to use:
PropertyInfo pi = #`Counter`
FieldInfo pi = #`_counter`
MethodInfo mi = #`Display()`
MethodInfo mi = #`String.Equals(String, String)`

This syntax can be ambiguity in the choice between the field and the property, which can be solved as follows:

Assembly asm = #`assembly:System.Reflection`
Type type = #`type:System.String`
PropertyInfo pi = #`property:Counter`
FieldInfo fi = #`field:counter`
MethodInfo mi = #`method:Display()`
MethodInfo mi = #`method:String.Equals(String, String)`

269 votes
Vote
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    I agree to the terms of service
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Pavel Evgenjevich TimoshenkoPavel Evgenjevich Timoshenko shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    7 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      I agree to the terms of service
      Signed in as (Sign out)
      Submitting...
      • Pavel Evgenjevich TimoshenkoPavel Evgenjevich Timoshenko commented  ·   ·  Flag as inappropriate

        The programming language should consist of naturally intuitive and coherent keywords.
        The process of the development of language is that it will eventually getting clear and agile grammar.
        For example, our programming language has a grammatical shortcoming.
        Take the operator "typeof". It is very similar to the method. In this case, it may be a reasonable question.
        What type of data of the argument is passed to the operator "typeof" which is very similar to the method?
        Right! This is not a data type, and it is unclear what! The same problem have delegates.
        We can write the following line:
        Func<String, String, Boolean> equals = String.Equals;
        The compiler will understand us correctly. It will automatically create a wrapper class.
        But understandably the compiler will generate an error if I try to write a following line
        Sting str = (String.Equals).ToString();
        Obviously initially we had to go the other way. We just had to use dynamic strings:
        Type type = `System.String`;
        MethodInfo mi1 = `System.String.Equals(String, String)`;
        MethodInfo mi2 = `Boolean System.String.Equals(Object, Object)`;
        var eq = mi1("a", "b");
        Func<String, String, Boolean> equals = mi2;
        class A { public Boolean Equals(String str1, String str2) {...}
        ...
        Func<String, String, Boolean> equals = `Equals`;
        or
        Func<String, String, Boolean> equals = `Boolean this.Equals(String, String)`;
        ...}
        A a = new A();
        Func<String, String, Boolean> equals = `a.Equals`;
        or `a.Equals`("A", "B");
        ...
        MethodInfo mi = `method: public String.IsNullOrEmpty`;
        ...
        Window win;
        PropertyInfo pi1 = `win.Title`;
        PropertyInfo pi2 = `String win.Title`;
        PropertyInfo pi3 = `private String myClass.MyPrivateProperty`;
        PropertyInfo pi3 = `property: private String myClass.MyPrivateProperty`;
        ...
        Assembly asm1 = `mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`
        Assembly asm2 = `assembly:mscorlib`
        The scope "assembly" is applied to avoid ambiguous interpretation.

        And what if I want to get the string representation.
        In this case, you can call the method already known to all:
        `method:Boolean this.Equals(String, String)`.ToString(stringFormat)

        We can go further, if we assume that all objects of reflection inherited from the base class or interface (IReflection, Reflection). There can be implemented implicit conversion to a string representation:
        String str = `Boolean this.Equals(String, String)`;

        All of this features provides us with great dynamic opportunities and keeps our code clean.

        To improve performance, we may use a compiled string operation for conversion to string at compile time:
        String str = @`Boolean this.Equals(String, String)`;

        I'm not talking about other enjoyable opportunities:
        from `methods:public this` in m
        where m.Name.StartsWith("E")
        select m;

        from `properties: this` in m
        where m.Name.StartsWith("E")
        select m;

        from `properties:private String this{get;}` in m
        where m.Name.StartsWith("E")
        select m;

      • AnonymousAnonymous commented  ·   ·  Flag as inappropriate

        I would like to express my own views on this proposal. Of course, some might support the option of creating pseudofunction like nameof(...). This programming language has already such "miracle" named typeof(...). But if it looks like a function, It should behave like function. What type of its argument? That's why I would not want to have this kind of the cornerstones in my garden. Programming language should be as small as possible such hacks.

      • ArtyomArtyom commented  ·   ·  Flag as inappropriate

        The Constructors of Delegate class have illogical trick:

        protected Delegate(object target, string method);
        protected Delegate(Type target, string method);
        protected MulticastDelegate(object target, string method);
        protected MulticastDelegate(Type target, string method);

        This is a clear example of of unconsidered entering opportunities in the programming language.
        I see the use of DLR query strings can help solve this problem.

      • Anonymous commented  ·   ·  Flag as inappropriate

        This prevents a source code full text search to find the trace statement.

        It adds extra complexity to the C# .net environment. Method names are largely unchanged after the initial production release and any refactoring would need to take into account renaming the method name hard-coded in trace message strings.

        There should be both a method name and full class name including name space defined by the compiler as a string macro variable. These could be used if needed a compile time.

      • Pavel Evgenjevich TimoshenkoPavel Evgenjevich Timoshenko commented  ·   ·  Flag as inappropriate

        Antuan, I support this idea. It can significantly extend the dynamic language features, for example:

        ?`count methods:System.String` -> Int32

        ?`count public static methods[/Lower/]:System.String` -> Int32

        ?`public static methods[/Lower/]:System.String` -> MethodInfo[] or IEnumerable<MethodInfo>

        String conditionVariable = "/Lower|Upper/";
        var methods = from ?`public static methods[%conditionVariable%]:System.String` in m
        where ...
        select m;

        if (?`.` != ?`MyClass.TestMethod`) ...

      • AntuanAntuan commented  ·   ·  Flag as inappropriate

        Implementation of the DLR-query expression (DLR-QE) feature is extremely necessary! But the symbol '#' may be replaced by a question mark '?'. It is also possible to use the dot symbol '.' for referring to the current context. The concept of scope can be used to specify nested contexts:

        [QSM]`[scope:] expression`

        [QSM] - DLR-query string modifier:
        none - output full format string (i.e. "NS.NSTest.TestClass.TestNestedClass.TestProperty" for property, "NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)" for method, "NS.NSTest.TestClass.TestNestedClass" for class, "NS.NSTest" for namespace)
        ~ - output short format string (i.e. "TestProperty" for property, "TestMethod" for method, "TestNestedClass" for class, "NS.NSTest" for namespace)
        ? - output object from System.Reflection namespace (PropertyInfo for property, MethodInfo for method, Type for class/struct, ... Assembly for assembly)

        [expression] - a required parameter defines the element to be converted. The dot symbol '.' uses for referring to the current context.
        [scope] - optional parameter indicates the scope for the expression: assembly, namespace, class, method, property, auto = callee[default], arguments

        `.` -> "NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)"
        `auto:.` -> "NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)"
        ~`.` -> "TestMethod"
        ~`auto:.` TestMethod
        ?`.` -> MethodInfo for NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)
        ?`auto:.` -> MethodInfo for NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)

        ?`method:.` -> MethodInfo for NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)
        ?`method:TestMethod` -> MethodInfo for NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)
        ?`method:String NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)` -> MethodInfo for String NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)

        ?`class:.` -> ClassInfo for NS.NSTest.TestClass.TestNestedClass
        ?`class:TestMethod` -> ClassInfo for NS.NSTest.TestClass.TestNestedClass
        ?`class:String NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String)` -> ClassInfo for NS.NSTest.TestClass.TestNestedClass

        `nested classes:.` -> "NS.NSTest.TestClass, NS.NSTest.TestNestedClass"
        `nested classes[]:.` -> ["NS.NSTest.TestClass", "NS.NSTest.TestNestedClass"]
        ~`nested classes:.` -> "TestClass, TestNestedClass"
        ?`nested classes:.` -> ClassInfo[] for [NS.NSTest.TestClass.TestNestedClass, NS.NSTest.TestClass]

        `classes:NS.NSTest` -> "NS.NSTest.TestClass, NS.NSTest.TestPublicClass"
        `classes[]:NS.NSTest` -> ["NS.NSTest.TestClass", "NS.NSTest.TestPublicClass"]
        `public classes:NS.NSTest` -> "NS.NSTest.TestPublicClass"
        ?`classes:.` -> ClassInfo[] for [NS.NSTest.TestClass, NS.NSTest.TestPublicClass]
        ?`public classes:NS.NSTest` -> ClassInfo[] for [NS.NSTest.TestPublicClass]

        ~`methods:NS.NSTest.TestClass exclude System.Object` -> "PublicMethod, ProtectedMethod, ProtectedInternalMethod, InternalMethod, PrivateMethod" (all methods exclude System.Object)
        ?`private or public or protected internal methods:.` -> in NS.NSTest.TestClass.PrivateMehtod context rerutns MethodInfo[] for [PublicMethod, PrivateMethod, ProtectedInternalMethod]

        ~`methods[/^Pr/i]:NS.NSTest.TestClass` -> "ProtectedMethod, ProtectedInternalMethod, PrivateMethod"

        .. - base context of current context
        `..` -> in NS.NSTest.TestClass.TestNestedClass.TestMethod(String, String) context returns "NS.NSTest.TestClass.TestNestedClass"

        `inherited class:.` -> "System.Object"
        ~`inherited class:.` -> "Object"
        ?`inherited class:.` -> Type for System.Object

        `interfaces:.` -> Type[] for [NS.NSTest.Interface1, NS.NSTest.Interface2]
        `interface[1]:.` -> Type for NS.NSTest.Interface1

        ----
        Message sign:6548dd9d687f830ce30c1765573010b5

      Feedback and Knowledge Base