Click here to Skip to main content
15,879,535 members
Articles / Programming Languages / C#

Talking About “nameof” Operator

Rate me:
Please Sign up or sign in to vote.
4.96/5 (18 votes)
8 Feb 2016CPOL11 min read 24.6K   180   7   6
In this article I would like to discuss about “nameof” operator supported by C# 6. It allows to map strings to named code elements.

Introduction

In some way, the article is a continuation the previous one entitled “What if names would contain white spaces?”. It's a part of series of articles devoted to the latest C# and Java programming language features.

In this article I would like to discuss about “nameof” operator supported by C# 6. It allows to map strings to named code elements. It's really useful feature within your code for some reasons. In order to understand the main areas of its application, let's consider following examples.

Example 1: Exceptions Handling

The main reason to add “nameof” is exceptions handling. When throwing an “ArgumentException” and its derivatives, you'd use a string for the name of the corresponding parameter that was invalid. Unfortunately, these strings had no compile time validation and any code changes (such as renaming classes, methods, properties, fields and variables) wouldn't automatically update the string, resulting in an inconsistency that was never caught by the compiler.

C#
void SomeMethod<T>(T value) {
  if (value == null)
    throw new ArgumentNullException(paramName: nameof(value)); 

  if (!(typeof(T) is Iinterface))
    throw new ArgumentException (nameof(T),
      $"Type '{typeof(T)}' does not support the method" +
       $"' { nameof(MyNamespace.MyClass)}.{nameof(SomeMethod)}'." );
    //Output: Type 'SomeType' does not support the method 'MyClass.SomeMethod'.
}

It's also possible to write the following code, although the method isn't static:

C#
$"Type '{typeof(T)}' does not support the method "+
 $"'{nameof(MyNamespace.MyClass.SomeMethod)}'." 
//Type 'MyNamespace.SomeType' does not support the method 'SomeMethod'.

I want to write “MyNamespace.MyClass.SomeMethod” in “nameof” literally, but the compiler cut my string to “SomeMethod”. So the operator name completely satisfies to the expected behavior. It should be kept in mind when writing code.

Example 2: Notifiable Properties

The other reason widely presented in publications about new features of C# 6 is improving code of “OnPropertyChanging” and “OnPropertyChanged” event raising of “INotifyPropertyChanging” and “INotifyPropertyChanged” interfaces, respectively. The interfaces notify clients that a property value is changing or has already changed.

C#
public class SomeClass : INotifyPropertyChanging, INotifyPropertyChanged {
  // From the INotifyPropertyChanging interface
  public event PropertyChangingEventHandler PropertyChanging; 

  protected virtual void OnPropertyChanging(String propertyName) {
    var handler = PropertyChanging;
    if (handler != null) handler(this, new PropertyChangingEventArgs(propertyName));} 

  // From the INotifyPropertyChanged interface 
  public event PropertyChangedEventHandler PropertyChanged; 

  protected virtual void OnPropertyChanged(String propertyName) {
    var handler = PropertyChanged;
    if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));} 

  public const String DEFAULT_SOME_TEXT = "Default value";
  private String _someText = DEFAULT_SOME_TEXT;

  [DefaultValue(DEFAULT_SOME_TEXT)]
  public String SomeText {
    get { return this._someText; } 
    set { 
      if ( String.Equals( this._someText, value , 
        StringComparison.CurrentCultureIgnoreCase))
        return;

      // Old code:
      OnPropertyChanging("SomeText");
      // or (see NameOfExt extension class)
      OnPropertyChanging(this.NameOf( o => SomeText ));
      // New Code:
      OnPropertyChanging(nameof(SomeText)); 

      this ._someText = value ; 

      // Old code:
      OnPropertyChanged("SomeText");
      // or (see NameOfExt extension class)
      OnPropertyChanged(this.NameOf( o => SomeText ));
      // New Code:
      OnPropertyChanged(nameof(SomeText)); 
    } 
  } 
}

The code is a very good example of how useful the new possibilities of C# 6 are. Almost every developer wrote similar code and knows how difficult is to keep in mind properly names of the properties described as a string. However, it isn't necessary to write the name of the caller property when the “System.Runtime.CompilerServices.CallerMemberNameAttribute” attribute appeared in .NET 4.5. This attribute enables to decorate method arguments, indicating that the appropriate piece of information is injected into that argument when the method is called.

C#
protected virtual void OnPropertyChanging(
  [CallerMemberName] String propertyName = "") { ... }

protected virtual void OnPropertyChanged(
  [CallerMemberName] String propertyName = "") { ... }
...
// Old code:
//  OnPropertyChanging("SomeInt");
// or (see NameOfExt extension class)
//  OnPropertyChanging(this.NameOf(o=>SomeInt));
// New Code (C# 6):
//  OnPropertyChanging(nameof(SomeInt));
// The better code without C# 6 feature
OnPropertyChanging();

this._someInt = value;

// Old code:
//  OnPropertyChanged("SomeInt");
// or (see NameOfExt extension class)
//  OnPropertyChanging(this.NameOf(o=>SomeInt));
// New Code (C# 6):
//  OnPropertyChanged(nameof(SomeInt));
// The better code without C# 6 feature
OnPropertyChanged();

These classes are very popular in a wide range of projects. For example, the WPF makes it possible to use the “INotifyPropertyChanged” interface. If the object in the “DataContext” property implements this interface, WPF will listen for its “PropertyChanged” event. This event signals changes to property values. When the event is raised, it indicates a change to a UI control binding and the displaying value changes accordingly. So there are more compact solutions.

C#
[Serializable]
public class SomeClass : INotifyPropertyChanging, INotyfyPropertyChanged {
#pragma warning disable 0067 // The event raised by PropertyExt extensions

  // From the INotifyPropertyChanging interface
  [field: NonSerialized]
  public event PropertyChangingEventHandler PropertyChanging;

  // From the INotifyPropertyChanged interface
  [field: NonSerialized]
  public event PropertyChangedEventHandler PropertyChanged;

#pragma warning restore 0067

  public const String DEFAULT_SOME_TEXT = "Default value";
  private String _someText = DEFAULT_SOME_TEXT;

  [DefaultValue(DEFAULT_SOME_TEXT)]
  public String SomeText {
    get { return this._someText; }
    set { this.SetPropertyAndNotify(ref _someText, value); }
  }

  public const Int32 DEFAULT_SOME_INT = 123;
  private Int32 _someInt = DEFAULT_SOME_INT;

  [DefaultValue(DEFAULT_SOME_INT)]
  public Int32 SomeInt {
    get { return this._someInt; }
    set { this.SetPropertyAndNotify(ref _someInt, value); }
  }
}

The extension method “SetPropertyAndNotify” may have the following implementation:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;

public static class PropertyExt {
  public static void SetPropertyAndNotify<t>(
    this INotifyPropertyChanged source,
    ref T field,
    T value,
    [CallerMemberName] String propertyName = "",
    EqualityComparer<t> equalityComparer = null)
  {
    if (source == null)
      throw new ArgumentNullException("source");

    if (!(equalityComparer ?? EqualityComparer<t>.Default).Equals(field, value)) {
      if (source is INotifyPropertyChanging) {
        RaiseEvent(source, "PropertyChanging",
          new PropertyChangingEventArgs(propertyName));
      }

      field = value;

      RaiseEvent(source, "PropertyChanged",
        new PropertyChangedEventArgs(propertyName));
    }
  }

  private static void RaiseEvent<teventargs>(
    this Object source,
    String eventName,
    TEventArgs eventArgs)
    where TEventArgs : EventArgs
  {
    var eventDelegate = (MulticastDelegate)source.GetType()
      .GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic)
      .GetValue(source);

    var parameters = new Object[] { source, eventArgs };

    foreach (var handler in eventDelegate.GetInvocationList()) {
      handler.Method.Invoke(handler.Target, parameters);
    }
}}</teventargs></t></t></t>

As mentioned earlier, there are many good solutions where there is no need to use the operator “nameof”: “MVVM Light” (“NuGet PM: Install-Package MvvmLight”), “AOP PostSharp” (“NuGet PM: Install-Package PostSharp”; see also “AOP Implementation of INotifyPropertyChanged”), “Kind of Magic” (CodePlex, VS Gallery). Furthermore, in certain cases, the operator may become the reason of writing of a low-quality code.

For compatibility with legacy code, it can avoid the “nameof” operator via helper methods based on tree expressions.

C#
using System; 
using System.Linq.Expressions; 

namespace Example { 
  public static class NameOfExt { 
    public static String NameOf(Expression<action> accessor) {
      return InternalNameOf(accessor); } 

    public static String NameOf<t>(Expression<func<t>> accessor) {
      return InternalNameOf(accessor); } 

    public static String NameOf<t, u="">(this T obj, Expression<func<t, u="">> accessor) {
      return InternalNameOf(accessor); } 

    private static String InternalNameOf(Expression expression) { 
      if (expression == null )
        throw new ArgumentNullException ( "expression" ); 

      if (expression is LambdaExpression )
        return _NameOf((( LambdaExpression ) expression).Body); 

       if (expression is UnaryExpression )
        return NameOf((( UnaryExpression ) expression).Operand); 

      var memberExpression = expression as MemberExpression ;
      if (memberExpression != null )
        return memberExpression.Member.Name; 

      MethodCallExpression methodExpression = expression as MethodCallExpression ;
      if (methodExpression != null )
        return methodExpression.Method.Name; 

      throw new ArgumentException (
      "The 'expression' should be a member expression or a method call expression." , 
      "expression" ); 
    }
  } 

  internal class Program {
    internal static void Main(string[] args) {
      var str = "Some String"; 

      // Gets the name of an object's property: " Length" .
      Console .WriteLine(str.NameOf(o => o.Length)); 
      // Gets the name of an object's method: " GetType" .
      Console .WriteLine(str.NameOf(o => o.GetType())); 
      // Gets the name of a class' property: " Empty ".
      Console .WriteLine( NameOfExt .NameOf(() => String .Empty)); 
      // Gets the name of a class' method: "Copy" .
      Console.WriteLine(NameOfExt.NameOf(() => String.Copy("")));
 }}} </func<t,></t,></func<t></t></action>

Similar code was written before the appearance of “nameof” operator. But “nameof” becomes a string constant during compilation instead of execute code to obtain name of code element by using tree expressions or reflection methods. So the introduced operator is a big advantage of C#, but it's also a disadvantage too. The possibilities of JIT-compiler isn't involved. It doesn't allow to predict the dynamic code changes and to substitute the name rightly. Besides, there is no opportunity to transform part of a code to string by principle “as is” to track its further changes: “System.Math.PI”, “Type Property” or “Type Namespace.Class.Method(Type arg0, Type arg1, ...)”. Functional style of the operator is perhaps doubtful. I'd want to ask a question: what type of argument? But the question disappears, because already there are similar methods like “typeof”. In addition, after compilation the method-like operator is replaced by string. Perhaps, it would be more natural to expand functionality of the string interpolation for strict and literally transform parts of code to string with validating it at compile time:

C#
$"'\@{MyNamespace.SomType}', '\@{SomType arg0}', '\@{arr[index]}'." 
//'MyNamespace.SomeType', 'SomType arg0', 'arr[index]'.
$"'\@{MyNamespace.{SomeType}}', '\@{{SomType} arg0}', '\@{{public }int {Prop}}'." 
//'SomeType', 'SomeType', 'public Prop'. The braces used for the selective conversion

The probability of that the “nameof” operator will be a part of interpolated string is very high. The offered syntax of refactorable strings may be applied conveniently in the comments:

C#
// This comment contains the name of @{MyNamespace.SomeType} type that
// sensible to the code refactoring.

In case of the self-documented comments similar functionality is partially available:

C#
/// <summary>
/// This method performs some operations on 
/// <paramref name="x"/> and <paramref name="y"/> arguments.
/// </summary>
/// <param name="x">The first argument</param>
/// <param name="y">The second argument</param>
/// <returns></returns>
Double Method(Double x, Double y) { ... }

/// <summary> 
/// The <code>SomeMethod</code> demonstates ... 
/// </summary> 
/// <typeparam name="T"> The template parameter </typeparam> 
/// <param name="value"> The input argument </param> 
void SomeMethod<T>(T value) { 
  // The 'value' parameter couldn't be null. 
  if (value == null )
  ... }

Let's show real practical usage of “nameof” in object notifications at last. You may ask a question based on the foregoing examples. Where can it be useful, when a good implementation of “INotifyPropertyChanged” interface doesn’t contain it? It's necessary to remember that the “PropertyChanged” event has subscribers. The expected action can't be performed, if the property name is defined incorrectly.

C#
private static void NPCSubscriber_PropertyChanged(
  Object sender,
  PropertyChangedEventArgs e)
{
  switch (e.PropertyName) {
    case nameof(ISomeClass.SomeInt): // "SomeInt"
    ... // Perform action 1
    break;
    case nameof(ISomeClass.SomeText): // "SomeText"
    ... // Perform action 2
    break;
    default:
      throw new InvalidOperationException();
  }
}

It should be kept in mind when the “NPC” class (contained “Notify Property Changed” event) designing, the operator “nameof” defined in a subscriber can't access to hidden members:

C#
class ClassWithHiddenMembers {
  protected Int32 Protected { get { return _protected; } }
  protected Int32 _protected;
}
class ClassForTestingOfPrivateMembersAccess {
  public override string ToString()
    => $"{nameof(ClassWithHiddenMembers._protected)}, "
     + $"{nameof(ClassWithHiddenMembers.Protected)}";
  // Error: It's inaccessible due to its protection level
}

The example of “PropertyChanged” subscriber implementation is very revealing. The properties which notify changes are grouped in the separate interface. It can improve readability and in some cases, the hidden members can be implemented explicitly:

C#
internal interface IClassWithHiddenMembers {
  Int32 Protected { get; }
}
class ClassWithHiddenMembers : IClassWithHiddenMembers {
  protected Int32 Protected { get { return _protected; } }
  Int32 IClassWithHiddenMembers.Protected {
    get { return _protected; }
  }

  protected Int32 _protected;
}

The example of “PropertyChanged” subscriber implementation has another weakness. The compared properties in “switch” operator are presented as strings that pass very poor information about it. If there is a lot of string names for comparison, the “switch”-design becomes ineffective and reduces the performance slightly. It would be desirable to compare references instead of strings. So, sometimes there is a wish to write following code:

C#
[Serializable]
public class NPC : INotifyPropertyChanged {
  #region "INotifyPropertyChanged" interface implementation

  [field:NonSerialized]
  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged([CallerMemberName] String propertyName = "") {
    OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  }

  protected virtual void OnPropertyChanged(PropertyChangedEventArgs evt) {
    if (evt == null) return;
    var handler = PropertyChanged;
    if (handler != null) handler(this, evt);
  }

  #endregion "INotifyPropertyChanged" interface implementation

  public const String DEFAULT_SOME_TEXT = "Default value";
  public static readonly PropertyChangedEventArgs CHANGED_SOME_TEXT_EVENT_ARGS 
    = new PropertyChangedEventArgs(nameof(SomeText));
  private String _someText = DEFAULT_SOME_TEXT;

  [DefaultValue(DEFAULT_SOME_TEXT)]
  public String SomeText {
    get { return this._someText; }
    set {
      if (String.Equals(this._someText, value,
        StringComparison.CurrentCultureIgnoreCase))
        return;

      this._someText = value;

      OnPropertyChanged(CHANGED_SOME_TEXT_EVENT_ARGS);
    }
  }

...

public static void Npc_SomeTextPropertyChanged(
  Object sender, PropertyChangedEventArgs e) {
  if (e == NPC.CHANGED_SOME_TEXT_EVENT_ARGS) {
    // Perform action
}}

Surprisingly, the “PropertyChangedEventArgs” class and others classes inherited from “EventArgs” aren't overloaded “Equals” methods. It would have to look like following code:

C#
public class PropertyChangedEventArgsEx: EventArgs {
  public PropertyChangedEventArgsEx(string propertyName) {
    this.PropertyName = propertyName; }

  public virtual string PropertyName { get; private set; }

  public override Boolean Equals(Object obj) {
    return Object.ReferenceEquals(this, obj)
    || ((obj is PropertyChangedEventArgsEx)
      && String.Equals(PropertyName, ((PropertyChangedEventArgsEx)obj).PropertyName))
    || base.Equals(obj);
  }
}

Why so often not to implement the “Equals” method? Maybe the answer would be simple. It's very difficult to keep that in mind, especially if you don't know how the class will be used. In addition, the methods “GetHashCode” and “ToString” are required to implement too, because the warning “CS0659” appeared. So there is a wish to take advantage of AOP.

C#
[^__strong__^Equals]
public class PropertyChangedEventArgsEx: EventArgs {
  public PropertyChangedEventArgsEx(String propertyName)
  { this.PropertyName = propertyName; }

  public virtual String PropertyName { get; private set; }

}

For example, there is an extensible tool “Fody” for weaving .NET assemblies. It has the good “Equals” generator “Fody/Equals” (“NuGet PM: Install-Package Equals.Fody”). It generate “Equals”, “GetHashCode” and operators methods from properties for class decorated with a “[Equals]” attribute. Also the tool “Fody/PropertyChanged” (“NuGet PM: Install-Package PropertyChanged.Fody”) provides an easy way to inject “INotifyPropertyChanged” code into properties at compile time.

Example 3: Reflection

Reflection are used for obtaining metadata of assembly and type structure at runtime. The classes that give access to the metadata of a running program are in the “System.Reflection” namespace. Also the reflection allows creating new code at runtime and then performs it dynamically. Quite large number of articles is devoted to it, for example: “Reflection in .NET”, “Reflection optimization techniques”, “Reflection with Example”, “Dynamic Type Using Reflection.Emit”, “HyperDescriptor: Accelerated dynamic property access”, “ExpressionToCode, Passert”, “Creating static methods at runtime”, “Reflection is Slow or Fast? A Practical Demo” and etc.

There can be an impression that the dynamic programming improvements was suspended after the addition of “dynamic” keyword. But this is not true. The next “dynamic” step could give the “nameof” operator. A lot of sources containing a reflection methods have a string names of finding or creating members. In such cases it's very convenient to use “nameof” operator. Let's look back to the example of “NPC” code. Properties could have values by default described by “System.ComponentModel.DefaultValueAttribute”. The value of attribute can be only obtained by reflection.

C#
[DefaultValue(DEFAULT_SOME_TEXT)]
public String SomeText {
  get { return this._someText; }
  set {
    if (String.IsNullOrEmpty(value)) {
      value = GetType()
        .GetProperty(nameof(SomeText))
        .GetCustomAttribute<defaultvalueattribute>().Value as String;
    }

    if (String.Equals(this._someText, value,
        StringComparison.CurrentCultureIgnoreCase))
      return;

    this._someText = value;

    OnPropertyChanged();
  }}</defaultvalueattribute>

The example above demonstrates how the “nameof” operator is useful in reflection. However, it shows the weakness of reflection. It's necessary to perform too much low-productive  operations to obtain required attribute. The code scope is known at compile time, but it needs to obtain it “dynamically” by processing of countless string arguments and list enumerations. But the getting attribute information is the most popular action of reflection. It should be simple and more efficient.

After looking at “PropertyChangedEventArgs” class in “PropertyChanged” event again, appears a clear understanding that, perhaps, “PropertyName” should be named “Property” with type “System.Reflection.PropertyInfo”. This type has the correctly implemented methods “Equals” and “ToStrinsg” and has a sufficient information to make a decision how it should compare and convert to string. However, the classes located in “System.Reflection” namespace aren't advisable to use for some reasons. It seems that the dynamics is slow and it breaks down the object oriented principles. Therefore it should be kept separately and be used only in rare cases. But in real projects, the situation around the reflection in C# is similar of the “#define” preproccessor directive being used in C++: “C Preprocessor tricks, tips, and idioms” or “What are some tricks I can use with macros?”. It's required to use it only where impossible avoid it. However, in real projects, the directive is applied everywhere. Today, there is a wide gap between native programming and meta-programming (reflecting, DLR) in C#. Perhaps, the gap needs to be reduced. Let's imagine how it might be done.

A lot of arguments of reflected elements passed to its methods have string type. Performing string conversions and dynamic binding requires considerable time. However, it's often necessary to refer to an existing code element placed in the current or public context (scope) or to reflect it.   If this is taken into account, it's possible to significantly improve the performance. Let's consider the following code.

C#
namespace ReflectionPatterns {
  public reflecting field pattern _field1; // Any field with name "_field1"
  public reflecting field pattern Int32 _field2;
  [RequireAttribute(typeof(SerializableAttribute))]
  public reflecting field pattern Int32 _field3;
  [TypeCast][AnyName][Static][MemberScope(Scope.Private | Scope.Internal)]
  public reflecting field pattern Object PrivateOrInternalFieldWithAnyName;
  [TypeCast][RegularExpression(@"^_field\d+$")]
  public reflecting field pattern Object FieldWithRegExprName;

  public reflecting property pattern Property1; // Any property with name "Property1"
  public reflecting property pattern Int32 Property2 {get;} // Getter is required
  public reflecting property pattern Int32 Property3 {set;} // Setter is required
  [TypeCast][AnyName][field:RequireAttribute(typeof(SerializableAttribute))]
  public reflecting property pattern Int32 PropertyWithAnyName {get; set;}
  [RegularExpression(@"^Property\d+$")]
  public reflecting property pattern PropertyWithRegExprName;

  public reflecting event pattern Event1; // Any event with name "Event1"
  public reflecting event pattern EventHandler Event2;
  [TypeCast][AnyName][MemberScope(Scope.Public | Scope.Protected)]
  public reflecting event pattern EventHandler PublicOrProtectedEventWithAnyName;
  [TypeCast][RegularExpression(@"^.*?Event(?:\d+)?$")]
  public reflecting event pattern EventWithRegExprName;

  public reflecting method pattern Method; // Any input and output arguments of
  // the method having name "Method"
  public reflecting method pattern Int32 Method1; // Any input arguments of
  // the method having name "Method1"
  [return:RequireAttribute(typeof(OutAttribute))]
  public reflecting method pattern Int32 Method2<t> where T:struct;
  // The pattern having dynamic substituted parts
  [DynamicType("MethodType")][DynamicName("MethodName")] 
  public reflecting method pattern Int32 MethodWithDynamicParts(
    [RegularExpression(@"^arg\d*$")] [DynamicName("ArgumentName")] T arg);

  [RegularExpression(@"^.*?Class(?:\d+)?$")]
  [BaseClassName(@"^Base.*?Class$")][InterfaceName(@"^I.*?Connection$")]
  [NestedPatern(Class1, Method1, Property1)][RequiredMembers(typeof(IInterface))]
  public reflecting class pattern ClassRegExprName : IInterface1, Iinterface2;
  // The class pattern may be used to define attribute patterns
}</t>

The reflecting pattern definition could be written and placed just like delegates. The patterns describe intuitively clear rules to find classes and its members statically and dynamically. The rules are a kind of dynamic language like “LINQ”. It adds native meta-information querying capabilities by the reflecting patterns and the set of extension methods. The patterns allows developers to understand visually that it is required to find. It also allows to check the syntax and to simplify searching queries during the compilation. In many cases the results of reflection can be given at the compile time. Getting the information corresponding to the reflecting pattern is performed by “reflect<T>(target)” operator. The template parameter “T” is reflection pattern or type being attribute or nesting to assembly or another type. The argument “target” is class instance, type or string.

C#
var fieldInfo1 = reflect<_field1>(this); // Exact match
var fieldInfos = reflect<PrivateOrInternalFieldWithAnyName[]>(typeof(SomeType));

var fieldInfo01 = reflect<_field1>(); // It calls for current scope
// and finds exact math
class SomeType {
public FieldInfo InstanceGetFieldInfo() {
  var fieldInfo = reflect<_field1>();
  // It's equivalent to
  // FieldInfo fieldInfo = reflect<_field1>(GetType())
  return fieldInfo;
}

public static FieldInfo StaticGetFieldInfo() {
  var fieldInfo = reflect<_field1>();
  // It's equivalent to
  // FieldInfo fieldInfo = reflect<_field1>(typeof(SomeType))
  return fieldInfo;
}

This approach can significantly simplify the way of interaction with the attributes.

C#
[^__strong__^DefaultValue(DEFAULT_SOME_TEXT)]
public String SomeText {
  get { return this._someText; }
  set {
    if (String.IsNullOrEmpty(value)) {
      value = reflect<DefaultValueAttribute>()?.Value as String;
    }

    if (String.Equals(this._someText, value,
        StringComparison.CurrentCultureIgnoreCase))
      return;

    this._someText = value;

    OnPropertyChanged();
  }}

The compiler can simplify the code presented above in the best way. Let's look at other examples.

C#
// Find methods that match the pattern "MethodPattern", 
// where the class placed in current assembly matches the pattern "ClassPattern"
MethodInfo[] mi = reflect<MethodPattern[], ClassPattern>();

// Find methods that match the pattern "MethodPattern", 
// where the class placed in custom assembly matches the pattern "ClassPattern"
MethodInfo[] mi = reflect<MethodPattern[], ClassPattern>(
"MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7779fa1be111eb0c");

// Maybe the reflection should be more strongly typed,
// then increase productivity and reduce errors.
FieldInfo<FieldPattern> fieldInfo = reflect<FieldPattern>();
MethodInfo<MethodPattern> methodInfo = reflect<MethodPattern>();
MethodInfo<PropertyPattern> propertyInfo = reflect<PropertyPattern>();

// Errors can be detected at compile time. The boxing/unboxing doesn't apply.
OldValue = propertyInfo.GetValue(this); propertyInfo.SetValue(this, NewValue);
methodInfo.Invoke(this, arg0, arg1, ..., argN);

// Using dynamically substituted parts (see example above)
MethodInfo<MethodWithDynamicParts> methodInfo = reflect<MethodWithDynamicParts>(
 "Namespace.Class", new {MethodType = typeof(Int32), ArgumentName="argument0"});
);

The example of getting and setting property values and calling the method by reflection shows that a further feature is required. It is “typed references”.

The typed reference defined by “reference<T>(target)” operator. It's like “reflect” operator. The operator allows to make a link with property, event, method or field. Its implementation should be lightweight and be similar “references” in C++. Its performance should be close to the direct calling the part of code referred by one. The behavior of references should be similar to the members to which they refer. The assignment and equality of references could be defined as additional operations. In this case, the performance of NPC subscribers may be improved significantly by comparing the typed references instead of strings.

C#
namespace ReflectedTypes {
  [AnyName]
  public reflecting property pattern PropertyPattern {get;}
  public reference PropertyRef : PropertyPattern; // It's like delegate definition
  // A warning "It's better not to refer to the field" is accompanied 
  // a reference to field. 

  class NPC : INotifyPropertyChanged {
    ...
    public Int32 Property {
      get { return _property; }
      set {
        if (_property == value) return;
        _property = property;
        PropertyChanged(reference<PropertyRef>(this));
         // also reference<PropertyRef>(), reflect<PropertyPattern>(this)
      }
    }
    private Int32 _property;
  }
  class Program {
    static void NPCSubscriber(Object sender, PropertyChangedEventArgs e) {
      PropertyRef propRef = e.Property as PropertyRef;
      if (propRef != null && propRef is reference(NPC.Property)) {
        Console.WriteLine("Type: {0}, name: {0}, value: {1}",
          propRef.Container.GetType(), propRef, propRef.Reference);
          // "Container" is instance or Type in case of reference to static member.
          // "Reference" is auto-generated property, event or method wrapper.
      }
    }

    static void Main(string[] args) {
      var obj = new NPC();
      obj.PropertyChanged += NPCSubscriber;
    }
}}

It may seem that the references are not necessary due to already existing delegates. However, their heavy functional possibilities shouldn't be required in many cases excepting events. All features of delegate (see source code of “Delegate” and “MulticastDelegate” classes) can be written transparently by typed references in ordinal classes without any hacks:

C#
public abstract class Delegate : ICloneable, Iserializable {
  // _target is the object we will invoke on
  [System.Security.SecurityCritical]
  internal Object _target;

  // MethodBase, either cached after first request or assigned from a DynamicMethod
  // For open delegates to collectible types, this may be a LoaderAllocator object
  [System.Security.SecurityCritical]
  internal Object _methodBase;

  // _methodPtr is a pointer to the method we will invoke
  // It could be a small thunk if this is a static or UM call
  [System.Security.SecurityCritical]
  internal IntPtr _methodPtr;

  // In the case of a static method passed to a delegate, this field stores
  // whatever _methodPtr would have stored: and _methodPtr points to a
  // small thunk which removes the "this" pointer before going on
  // to _methodPtrAux.
  [System.Security.SecurityCritical]
  internal IntPtr _methodPtrAux;

  // This constructor is called from the class generated by the
  //  compiler generated code
  [System.Security.SecuritySafeCritical] // auto-generated
  protected Delegate(Object target, String method) {
    if (target == null)
      throw new ArgumentNullException("target");

    if (method == null)
      throw new ArgumentNullException("method");
    Contract.EndContractBlock();

    if (!BindToMethodName(target, (RuntimeType)target.GetType(), method,
      DelegateBindingFlags.InstanceMethodOnly |
      DelegateBindingFlags.ClosedDelegateOnly))
    throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTargMeth"));
  }
...
  [System.Security.SecurityCritical]  // auto-generated
  [ResourceExposure(ResourceScope.None)]
  [MethodImplAttribute(MethodImplOptions.InternalCall)]
  private extern bool BindToMethodName(Object target,
    RuntimeType methodType, String method, DelegateBindingFlags flags);
...

  [System.Security.SecuritySafeCritical] // auto-generated
  protected virtual object DynamicInvokeImpl(object[] args) {
    RuntimeMethodHandleInternal method = 
      new RuntimeMethodHandleInternal(GetInvokeMethod());
    RuntimeMethodInfo invoke = 
      RuntimeType.GetMethodBase((RuntimeType)this.GetType(), method);

    return invoke.UnsafeInvoke(this, BindingFlags.Default, null, args, null);
  }
  ...
  [System.Security.SecuritySafeCritical]  // auto-generated
  protected virtual MethodInfo GetMethodImpl() {
    if ((_methodBase == null) || !(_methodBase is MethodInfo)) {
      IRuntimeMethodInfo method = FindMethodHandle();
      RuntimeType declaringType = RuntimeMethodHandle.GetDeclaringType(method);
      if(RuntimeTypeHandle.IsGenericTypeDefinition(declaringType)
        || RuntimeTypeHandle.HasInstantiation(declaringType)) {
        bool isStatic = (RuntimeMethodHandle.GetAttributes(method) 
                         & MethodAttributes.Static) != (MethodAttributes)0;
        if (!isStatic) {
          if (_methodPtrAux == (IntPtr)0) {
            Type currentType = _target.GetType();
            Type targetType = declaringType.GetGenericTypeDefinition();
            while (currentType != null) {
              if (currentType.IsGenericType
              && currentType.GetGenericTypeDefinition() == targetType) {
                declaringType = currentType as RuntimeType;
                break;
              }
              currentType = currentType.BaseType;
            }
            BCLDebug.Assert(currentType != null || _target.GetType().IsCOMObject,
              "The class hierarchy should declare the method");
          } else {
            MethodInfo invoke = this.GetType().GetMethod("Invoke");
            declaringType = (RuntimeType)invoke.GetParameters()[0].ParameterType;
          }
        }
      }
      _methodBase = (MethodInfo)RuntimeType.GetMethodBase(declaringType, method);
    }
    return (MethodInfo)_methodBase;
  }
  ...
}

By studying the code, it can be concluded that without the references it is not possible to write good-quality code. That is why the developers of C# create it by small hack (see “_methodPtr” or “_methodPtrAux” fields having internal accessibility). If there are no references, it have to use the slow reflection. There is a similar situation with classes placed in “System.Reflection” and “System.Dynamic” namespaces. So maybe it should append the typed references explicitly without any hacks?

The “reflect” and “reference” operators would be recommended to use for reflection. Maybe it's better approach compared with existing one. In most cases “.NET” would perform a pretty good optimization, because it's possible to predict what kind of information is needed at compile time. The various code could be created by compiler depending on the situation. Also it should be noted that the reflection becomes friendly to the developers by using ones.

Conclusion

I believe “nameof” operator provided new good opportunities to be entirely worthy of the attention. It will save us countless hours of fixing mistaken refactoring, arguing over coding style and code reviews, and head-scratching at implicit errors. On the other hand, it reveals some of the language issues, which should be properly investigated and made some improvements in C#. There are other very interesting issues that will be discussed in future articles.

I would greatly appreciate the opinion of readers who express their point of view and answer the question. Do you have any good practical examples of reflections (“System.Reflection”, “System.Reflection.Emit”, “System.Dynamic”, “Expression trees”, “dynamic”, and etc) used in real projects? It would be nice, if it would be possible to use the “nameof” operator in your examples.

Points of Interest

It's wonderful to find and learn the good software engineering principles, nice approaches in source code and modern frameworks allow us to write really flexible code.

History

09/02/2016 - First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer Southern Federal University
Russian Federation Russian Federation
Senior lecturer of Nanotechnology department of Physics faculty of Southern Federal University (Russia).

My field of science is the numerical modeling of excitation, propagation and receiving of electromagnetic and acoustic waves in micro- and nanostructures; modeling microwave and optic devices based on ferromagnetic, ferroelectric and semiconducting films and whiskers; study of the periodic structures properties like magnonic and photonic crystals.

I also develop a software for theoretical modeling and experimental studies using modern methods of software engineering, programming languages, numerical methods and mathematical software packages, software platforms, parallel computation and asynchronous programming, database management systems, Web-programming and design, system programming (drivers , communication interfaces, microcontroller programming).

My hobbies are software architecture (UP, UML, TDD, BDD, DI, AOP), programming languages (C#, F#, C++, Java, LabVIEW, Delphi, Perl, PHP, ASP.NET, JavaScript, VBScript, ActionScript, Pascal, Basic, VBA for MS Office, Fortran, Assembler, PowerShell, SQL, VHDL), mathematical methods and mathematical packages (Maple, MatLab, Mathematica), programming for modern electronics (microcontrollers, PLIS, DSP, communication interfaces), Web-design (design, HTML, Flash, Silverlight, Moodle, Joomla, Drupal), technologies (WPF, WCF, WF, ADO.NET, COM, Services, WMI, MFC, jQuery, YUI), System Administration (Windows, Unix), office suites (Microsoft Office, Libre Office, using styles, LaTeX).

Comments and Discussions

 
GeneralObfuscated reflection code Pin
Mario Z9-Feb-16 0:45
professionalMario Z9-Feb-16 0:45 
AnswerRe: Obfuscated reflection code Pin
Pavel Evgenjevich Timoshenko9-Feb-16 4:19
Pavel Evgenjevich Timoshenko9-Feb-16 4:19 
GeneralRe: Obfuscated reflection code Pin
Mario Z9-Feb-16 5:43
professionalMario Z9-Feb-16 5:43 
AnswerRe: Obfuscated reflection code Pin
Pavel Evgenjevich Timoshenko9-Feb-16 9:21
Pavel Evgenjevich Timoshenko9-Feb-16 9:21 
GeneralRe: Obfuscated reflection code Pin
Mario Z9-Feb-16 20:32
professionalMario Z9-Feb-16 20:32 
PraiseRe: Obfuscated reflection code Pin
Pavel Evgenjevich Timoshenko29-Feb-16 4:57
Pavel Evgenjevich Timoshenko29-Feb-16 4:57 
Thanks for Your attention!

Regards,
Pavel

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.