Interface Casting vs. Class Casting
I've been led to believe that casting can, in certain circumstances, become a measurable hindrance on performance. This may be moreso the case when we start dealing with incoherent webs of nasty exception throwing\catching.
Given that I wish to create more correct heuristics when it comes to programming, I've been prompted to ask this question to the .NET gurus out there: Is interface casting faster than class casting?
To give a code example, let's say this exists:
public interface IEntity { IParent DaddyMommy { get; } }
publi开发者_JAVA百科c interface IParent : IEntity { }
public class Parent : Entity, IParent { }
public class Entity : IEntity
{
public IParent DaddyMommy { get; protected set; }
public IParent AdamEve_Interfaces
{
get
{
IEntity e = this;
while (e.DaddyMommy != null)
e = e.DaddyMommy as IEntity;
return e as IParent;
}
}
public Parent AdamEve_Classes
{
get
{
Entity e = this;
while (e.DaddyMommy != null)
e = e.DaddyMommy as Entity;
return e as Parent;
}
}
}
So, is AdamEve_Interfaces faster than AdamEve_Classes? If so, by how much? And, if you know the answer, why?
A number of the answers here suggest benchmarking, which is a step in the right direction, but only the first step in the journey.
My team has done a great deal of profiling and benchmarking in this area. The short version is yes, there are situations in which interfaces impose a small but measurable performance cost. However the actual cost depends on a great many factors, including how many interfaces are supported, how many of those interfaces a given reference is cast to, what the pattern of accesses are, and so on. The CLR has a great many heuristics in place designed to speed up interface access in common cases.
If you are benchmarking one of those common cases, but your actual program falls into a less common case, then your benchmarking is actively harmful because it is giving you data that is misleading.
Far better to do realistic performance measurements on real code. Use a profiler, write the code both ways, and see whether either way is measurably, repeatably faster in a way that is visible and relevant to the user.
As for your reference to throwing and catching: the performance cost of throwing and catching should be irrelevant. Exceptions are by definition exceptional, not common. Furthermore, exceptions usually indicate that something is going to halt shortly; it usually doesn't matter whether something halts as fast as possible. If you are in a situation where your performance is gated by exceptions then you have bigger problems to solve: stop throwing so many exceptions. An exception thrown should be extremely rare.
You would have to measure.
But if casting is becoming a (potential) bottleneck in your code you're way past spaghetti on the problem menu.
Take a look at here:
http://thatstoday.com/robbanp/blog/6/25/csharp-performance--cast-vs-interface
And, yes, you seem to be right.
Edit Well, it seems that I was wrong. And like my "patrício" Martinho Fernandes commented bellow, the above link is completely bogus (but I'll keep it here, for the sake of honest editing).
I do have some spare time nowadays, so I've written a simple performance measuring code:
public partial class Form1 : Form
{
private const int Cycles = 10000000;
public interface IMyInterface
{
int SameProperty { get; set; }
}
public class InterfacedClass : IMyInterface
{
public int SameProperty { get; set; }
}
public class SimpleClass
{
public int SameProperty { get; set; }
}
public struct InterfacedStruct : IMyInterface
{
public int SameProperty { get; set; }
}
public struct SimpleStruct
{
public int SameProperty { get; set; }
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
var simpleClassTime = MeasureSimpleClass();
var interfacedClassTime = MeasureInterfacedClass();
var simpleStructTime = MeasureSimpleStruct();
var interfacedStructTime = MeasureInterfacedStruct();
var message = string.Format(
"simpleClassTime = {0}\r\ninterfacedClassTime = {1}\r\nsimpleStructTime = {2}\r\ninterfacedStructTime = {3}",
simpleClassTime,
interfacedClassTime,
simpleStructTime,
interfacedStructTime
);
textBox.Text = message;
}
private static long MeasureSimpleClass() {
var watch = Stopwatch.StartNew();
var obj = new SimpleClass();
for (var i = 0; i < Cycles; i++)
{
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
private static long MeasureInterfacedClass() {
var watch = Stopwatch.StartNew();
IMyInterface obj = new InterfacedClass();
for (var i = 0; i < Cycles; i++) {
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
private static long MeasureSimpleStruct()
{
var watch = Stopwatch.StartNew();
var obj = new SimpleStruct();
for (var i = 0; i < Cycles; i++)
{
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
private static long MeasureInterfacedStruct()
{
var watch = Stopwatch.StartNew();
IMyInterface obj = new InterfacedStruct();
for (var i = 0; i < Cycles; i++)
{
obj.SameProperty = i;
var j = obj.SameProperty;
obj.SameProperty = j;
}
return watch.ElapsedMilliseconds;
}
}
And the result is:
simpleClassTime = 274
interfacedClassTime = 339
simpleStructTime = 247
interfacedStructTime = 302
I really used to think that an interface would be faster for class
types, and slower for struct
(since boxing/unboxing is involved in the latter), but that is not the case: a concrete class/struct reference is always faster, it seems.
Also, to whom it may concern: I believe that performance is not a good criteria for deciding if an interface should or should not be used. The difference is, like others said here, negligible.
Have you tried testing it? Here's a loop that runs 10,000,000 times. On my machine the interface version takes about 440 ms and the class version about 410 ms. So pretty close but overall the class version wins.
using System;
namespace ConsoleApplication1
{
public interface IEntity { IParent DaddyMommy { get; } }
public interface IParent : IEntity { }
public class Parent : Entity, IParent { }
public class Entity : IEntity
{
public IParent DaddyMommy { get; protected set; }
public IParent AdamEve_Interfaces
{
get
{
IEntity e = this;
while (this.DaddyMommy != null)
e = e.DaddyMommy as IEntity;
return e as IParent;
}
}
public Parent AdamEve_Classes
{
get
{
Entity e = this;
while (this.DaddyMommy != null)
e = e.DaddyMommy as Entity;
return e as Parent;
}
}
}
class Program
{
static void Main(string[] args)
{
Entity X = new Entity();
Parent P;
IParent IP;
System.Diagnostics.Stopwatch ST = new System.Diagnostics.Stopwatch();
Int32 i;
ST.Start();
for (i = 0; i < 10000000; i++)
{
IP = X.AdamEve_Interfaces;
}
ST.Stop();
System.Diagnostics.Trace.WriteLine(ST.ElapsedMilliseconds);
ST.Reset();
ST.Start();
for (i = 0; i < 10000000; i++)
{
P = X.AdamEve_Classes;
}
ST.Stop();
System.Diagnostics.Trace.WriteLine(ST.ElapsedMilliseconds);
}
}
}
Assuming there are no static conversion operators defined, the cast should take the same time, roughly. There are potentially some "inlining" optimisations possible when invoking a method on a class rather than an interface, but that won't be noticed unless calling a method an insane number of times.
Over all; there is no significant performance issue with either. Or to put it another way: until I've profiled and shown this to matter, I'd look elsewhere first.
First of all, you do not need casting here as the code must work without casting. IParent
is an IEntity
so it should just work.
Does casting has an impact on performance? Slightly if it involves converting (if type implements IConvertible
and conversion is necessary). Otherwise it is negligible since all it has to do is to do a type check which should be lightning fast.
精彩评论