Share via


SYSK 21: How slow is invoking properties via reflection?

Ok, so we all know that reflection (run time discovery and invocation), a concept somewhat akin to late binding from COM days, is slower than calling those methods and properties directly (early binding, to continue the analogy). But how much slower is it?

 

To find out, I created a very simple test (source at the bottom)… Nothing special – just 10 class properties retrieved via reflection:
object currentValue = prop.GetValue(this, null);
and by invoking the property directly:
object currentValue = Prop1;

 

I do it in the loop, repeating the process 1000 times and measuring the duration in clock ticks (yes, I know, I could’ve used a high resolution timer, but I’m just trying to get a rough estimate)…

The result is that, on my laptop – Toshiba M2, 2GHz, 2 Mb – calling properties via reflection is about 4 times slower… I did change the order (first refection, then direct call; then switch to first direct call, then reflection) and measured it 3 times to make sure I get reasonably clean data…

 

Here are the actual timing results:

 

1000 iterations using hardcoded properties: 50 ms
1000 iterations using reflection: 210 ms

1000 iterations using hardcoded properties: 30 ms
1000 iterations using reflection: 210 ms

1000 iterations using hardcoded properties: 40 ms
1000 iterations using reflection: 240 ms

1000 iterations using reflection: 210 ms
1000 iterations using hardcoded properties: 40 ms

1000 iterations using reflection: 280 ms
1000 iterations using hardcoded properties: 20 ms

1000 iterations using reflection: 210 ms
1000 iterations using hardcoded properties: 20 ms

As you can see, in either case it’s microseconds per call; but, as we all know, good developers know the cost of an operation and make intelligent decisions on whether the “feature” is “worth using it” in a given context.

Source Code:

namespace WindowsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Class1 c1 = new Class1();
c1.Prop1 = DateTime.Now.Ticks.ToString();
c1.Prop2 = DateTime.Now.Ticks.ToString();
c1.Prop3 = DateTime.Now.Ticks.ToString();
c1.Prop4 = DateTime.Now.Ticks.ToString();
c1.Prop5 = DateTime.Now.Ticks.ToString();
c1.Prop6 = DateTime.Now.Ticks.ToString();
c1.Prop7 = DateTime.Now.Ticks.ToString();
c1.Prop8 = DateTime.Now.Ticks.ToString();
c1.Prop9 = DateTime.Now.Ticks.ToString();
c1.Prop10 = DateTime.Now.Ticks.ToString();

Class1 c2 = new Class1();
c2.Prop1 = DateTime.Now.Ticks.ToString();
c2.Prop2 = DateTime.Now.Ticks.ToString();
c2.Prop3 = DateTime.Now.Ticks.ToString();
c2.Prop4 = DateTime.Now.Ticks.ToString();
c2.Prop5 = DateTime.Now.Ticks.ToString();
c2.Prop6 = DateTime.Now.Ticks.ToString();
c2.Prop7 = DateTime.Now.Ticks.ToString();
c2.Prop8 = DateTime.Now.Ticks.ToString();
c2.Prop9 = DateTime.Now.Ticks.ToString();
c2.Prop10 = DateTime.Now.Ticks.ToString();

long t1 = DateTime.Now.Ticks;
string changes;
for (int i = 1; i < 1000; i++)
{
//changes = c1.ChangesHardcoded;
changes = c1.ChangesReflection;
}
long t2 = DateTime.Now.Ticks;

System.Diagnostics.Debug.Write(string.Format("1000 iterations using reflection: {0} ms\r\n", (t2-t1)/TimeSpan.TicksPerMillisecond));
//System.Diagnostics.Debug.Write(string.Format("1000 iterations using hardcoded properties: {0} ms\r\n", (t2 - t1) / TimeSpan.TicksPerMillisecond));

t1 = DateTime.Now.Ticks;
for (int i = 1; i < 1000; i++)
{
changes = c2.ChangesHardcoded;
//changes = c2.ChangesReflection;
}
t2 = DateTime.Now.Ticks;

System.Diagnostics.Debug.Write(string.Format("1000 iterations using hardcoded properties: {0} ms\r\n", (t2 - t1) / TimeSpan.TicksPerMillisecond));
//System.Diagnostics.Debug.Write(string.Format("1000 iterations using reflection: {0} ms\r\n", (t2 - t1) / TimeSpan.TicksPerMillisecond));

MessageBox.Show("Done");
}
}

[Serializable]
public class Class1
{
#region Private data member variables
private string _prop1 = "1";
private string _prop2 = "2";
private string _prop3 = "3";
private string _prop4 = "4";
private string _prop5 = "5";
private string _prop6;
private string _prop7;
private string _prop8;
private string _prop9;
private string _prop10;

private Class1 _prevData;

#endregion

#region ctor
public Class1()
{
_prevData = this.Clone();
}
#endregion

#region Public properties
public string Prop1
{
get { return _prop1; }
set { _prop1 = value; }
}

public string Prop2
{
get { return _prop2; }
set { _prop2 = value; }
}

public string Prop3
{
get { return _prop3; }
set { _prop3 = value; }
}

public string Prop4
{
get { return _prop4; }
set { _prop4 = value; }
}

public string Prop5
{
get { return _prop5; }
set { _prop5 = value; }
}

public string Prop6
{
get { return _prop6; }
set { _prop6 = value; }
}

public string Prop7
{
get { return _prop7; }
set { _prop7 = value; }
}

public string Prop8
{
get { return _prop8; }
set { _prop8 = value; }
}

public string Prop9
{
get { return _prop9; }
set { _prop9 = value; }
}

public string Prop10
{
get { return _prop10; }
set { _prop10 = value; }
}
#endregion

#region Changes
private string GetChanges(string propertyName)
{
string result = null;

System.Reflection.PropertyInfo prop = this.GetType().GetProperty(propertyName);
System.Diagnostics.Debug.Assert(prop != null);

object currentValue = prop.GetValue(this, null);
object prevValue = null;
if (_prevData != null)
prevValue = prop.GetValue(_prevData, null);

if (currentValue.Equals(prevValue) == false)
{
result = string.Format("{0} (old = {1}, new = {2})\r\n", propertyName, prevValue, currentValue);
}

return result;
}

public string ChangesHardcoded
{
get
{
System.Text.StringBuilder result = new System.Text.StringBuilder(256);

object currentValue = Prop1;
object prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop1;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop1", prevValue, currentValue);
}

currentValue = Prop2;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop2;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop2", prevValue, currentValue);
}

currentValue = Prop3;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop3;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop3", prevValue, currentValue);
}

currentValue = Prop4;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop4;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop4", prevValue, currentValue);
}

currentValue = Prop5;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop5;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop5", prevValue, currentValue);
}

currentValue = Prop6;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop6;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop6", prevValue, currentValue);
}

currentValue = Prop7;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop7;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop7", prevValue, currentValue);
}

currentValue = Prop8;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop8;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop8", prevValue, currentValue);
}

currentValue = Prop9;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop9;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop9", prevValue, currentValue);
}

currentValue = Prop10;
prevValue = null;
if (_prevData != null)
prevValue = _prevData.Prop10;
if (currentValue.Equals(prevValue) == false)
{
result.AppendFormat("{0} (old = {1}, new = {2})\r\n", "Prop10", prevValue, currentValue);
}

return result.ToString();
}
}

public string ChangesReflection
{
get
{
System.Text.StringBuilder result = new System.Text.StringBuilder(256);

result.Append(GetChanges("Prop1"));
result.Append(GetChanges("Prop2"));
result.Append(GetChanges("Prop3"));
result.Append(GetChanges("Prop4"));
result.Append(GetChanges("Prop5"));
result.Append(GetChanges("Prop6"));
result.Append(GetChanges("Prop7"));
result.Append(GetChanges("Prop8"));
result.Append(GetChanges("Prop9"));
result.Append(GetChanges("Prop10"));

return result.ToString();
}
}
#endregion

#region Clone
public Class1 Clone()
{
Class1 result = null;

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter f = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(null, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone));
System.IO.MemoryStream stream = new System.IO.MemoryStream();

f.Serialize(stream, this);
stream.Position = 0;
result = (Class1) f.Deserialize(stream);

stream.Close();

return result;
}
#endregion
}
}