C# 反射有多慢
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/771524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How slow is Reflection
提问by user29964
I recently created an interface layer to distinguish the DataAccessProvider from our Business logic layer. With this approach we can change our choice of DataAccessProvider whenever we want by changing the values in the Web/App.Config. (more details can be given if needed).
我最近创建了一个接口层来区分 DataAccessProvider 和我们的业务逻辑层。通过这种方法,我们可以随时通过更改 Web/App.Config 中的值来更改我们对 DataAccessProvider 的选择。(如果需要,可以提供更多详细信息)。
Anyway, to do this we use reflection to accomplish our DataProvider class on which we can work.
无论如何,要做到这一点,我们使用反射来完成我们可以工作的 DataProvider 类。
/// <summary>
/// The constructor will create a new provider with the use of reflection.
/// If the assembly could not be loaded an AssemblyNotFoundException will be thrown.
/// </summary>
public DataAccessProviderFactory()
{
string providerName = ConfigurationManager.AppSettings["DataProvider"];
string providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"];
try
{
activeProvider = Assembly.Load(providerName);
activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName);
}
catch
{
throw new AssemblyNotFoundException();
}
}
But now I'm wondering how slow reflection is?
但现在我想知道反射有多慢?
采纳答案by Marc Gravell
In most cases: more than fast enough. For example, if you are using this to create a DAL wrapper object, the time taken to create the object via reflection will be minusculecompared to the time it needs to connect to a network. So optimising this would be a waste of time.
在大多数情况下:足够快。例如,如果您使用它来创建 DAL 包装器对象,那么与需要连接到网络的时间相比,通过反射创建对象所花费的时间将是微不足道的。所以优化这将是浪费时间。
If you are using reflection in a tight loop, there are tricks to improve it:
如果你在一个紧凑的循环中使用反射,有一些技巧可以改进它:
- generics (using a wrapper
where T : new()
andMakeGenericType
) Delegate.CreateDelegate
(to a typed delegate; doesn't work for constructors)Reflection.Emit
- hardcoreExpression
(likeDelegate.CreateDelegate
, but more flexible, and works for constructors)
- 泛型(使用包装器
where T : new()
和MakeGenericType
) Delegate.CreateDelegate
(对于类型化委托;不适用于构造函数)Reflection.Emit
- 铁杆Expression
(像Delegate.CreateDelegate
,但更灵活,适用于构造函数)
But for your purposes, CreateInstance
is perfectly fine. Stick with that, and keep things simple.
但就你的目的而言,CreateInstance
完全没问题。坚持这一点,让事情变得简单。
Edit: while the point about relative performance remains, and while the most important thing, "measure it", remains, I should clarify some of the above. Sometimes... it doesmatter. Measure first. However, if you find it istoo slow, you might want to look at something like FastMember, which does all the Reflection.Emit
code quietly in the background, to give you a nice easy API; for example:
编辑:虽然关于相对性能的观点仍然存在,而最重要的事情仍然是“衡量它”,但我应该澄清上述一些问题。有时……确实很重要。先测量。但是,如果你发现它是太慢了,你可能想看看像FastMember,它完成了所有的Reflection.Emit
代码在后台悄悄,给你一个很好的方便的API; 例如:
var accessor = TypeAccessor.Create(type);
List<object> results = new List<object>();
foreach(var row in rows) {
object obj = accessor.CreateNew();
foreach(var col in cols) {
accessor[obj, col.Name] = col.Value;
}
results.Add(obj);
}
which is simple, but will be very fast. In the specific example I mention about a DAL wrapper—if you are doing this lots, consider something like dapper, which again does all the Reflection.Emit
code in the background to give you the fastest possible but easy to use API:
这很简单,但会非常快。在我提到的有关 DAL 包装器的具体示例中——如果您正在做很多事情,请考虑像dapper这样的东西,它再次Reflection.Emit
在后台执行所有代码,为您提供尽可能快但易于使用的 API:
int id = 12345;
var orders = connection.Query<Order>(
"select top 10 * from Orders where CustomerId = @id order by Id desc",
new { id }).ToList();
回答by Ruben Steins
回答by Martin Peck
Other than following the links given in other answers and ensuring you're not writing "pathalogically bad" code then for me the best answer to this is to test it yourself.
除了遵循其他答案中给出的链接并确保您没有编写“病态的”代码之外,对我来说最好的答案是自己测试。
Only you know where you bottle necks are, how many times your reflection code will be user, whether the reflection code will be in tight loops etc. You know your business case, how many users will access your site, what the perf requirements are.
只有你知道你的瓶颈在哪里,你的反射代码将被用户使用多少次,反射代码是否处于紧密循环等。你知道你的业务案例,有多少用户将访问你的站点,性能要求是什么。
However, given the snippet of code you've shown here then my guess would be that the overhead of reflection isn't going to be a massive problem.
但是,鉴于您在此处显示的代码片段,我的猜测是反射的开销不会成为一个大问题。
VS.NET web testing and performance testing features should make measuring the performance of this code pretty simple.
VS.NET Web 测试和性能测试功能应该使衡量此代码的性能变得非常简单。
If you don't use reflection, what will your code look like? What limitations will it have? It may be that you can't live with the limitations that you find yourself with if you remove the reflection code. It might be worth trying to design this code without the reflection to see if it's possible or it the alternative is desirable.
如果你不使用反射,你的代码会是什么样子?它会有什么限制?如果删除反射代码,您可能无法忍受自己遇到的限制。可能值得尝试在没有反射的情况下设计此代码,以查看它是否可能或替代方案是否可取。
回答by Enyra
Reflection is not THAT slow. Invoking a method by reflection is about 3 times slower than the normal way. That is no problem if you do this just once or in non-critical situations. If you use it 10'000 times in a time-critical method, I would consider to change the implementation.
反思并没有那么慢。通过反射调用方法比正常方法慢大约 3 倍。如果您只执行一次或在非危急情况下执行此操作,那没有问题。如果您在时间关键的方法中使用它 10'000 次,我会考虑更改实现。
回答by majkinetor
Its slower compared to non-reflective code. The important thing is not if its slow, but if its slow where it counts. For instance, if you instantiate objects using reflection in web environment where expected concurency can rise up to 10K, it will be slow.
与非反射代码相比,它更慢。重要的不是它是否慢,而是它在重要的地方是否慢。例如,如果您在 Web 环境中使用反射实例化对象,其中预期并发性可能会上升到 10K,那么它会很慢。
Anyway, its good not to be concerned about performance in advance. If things turns out to be slow, you can always speed them up if you designed things correctly so that parts that you expected might be in need of optimisation in future are localised.
不管怎样,不要提前关心性能是好的。如果事情变得很慢,如果你正确地设计了一些东西,你总是可以加快速度,这样你期望将来可能需要优化的部分被本地化了。
You can check this famous article if you need speed up:
如果你需要加速,你可以查看这篇著名的文章:
Dynamic... But Fast: The Tale of Three Monkeys, A Wolf and the DynamicMethod and ILGenerator Classes
回答by n8wrl
I was doing somethign similar until I started playing with IoC. I would use a Spring object definition to specify the data provider - SQL, XML, or Mocks!
在我开始玩 IoC 之前,我一直在做类似的事情。我将使用 Spring 对象定义来指定数据提供者 - SQL、XML 或 Mocks!
回答by Levi Fuller
I thought I'd do a quick test to demonstrate how slow reflection is compared to without.
我想我会做一个快速测试来演示与没有反射相比有多慢。
With Reflection
带反射
- Instantiating 58 objects by iterating through each of their Attributes and matching
Total Time: 52254 nanoseconds
while (reader.Read()) { string[] columns = reader.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute))); foreach (var property in rawPayFileAttributes) { int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index; if (propertyIndex < columns.Length) property.SetValue(toReturn, columns[propertyIndex]); else break; } }
- 通过迭代每个属性并匹配来实例化 58 个对象
总时间:52254 纳秒
while (reader.Read()) { string[] columns = reader.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute))); foreach (var property in rawPayFileAttributes) { int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index; if (propertyIndex < columns.Length) property.SetValue(toReturn, columns[propertyIndex]); else break; } }
Without Reflection
没有反射
- Instantiating 58 Objects by creating a new object
Total Time: 868 nanoseconds
while (reader2.Read()) { string[] columns = reader2.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { ColumnZero = columns[0], ColumnOne = columns[1], ColumnTwo = columns[2], ColumnThree = columns[3], ColumnFour = columns[4], ColumnFive = columns[5], ColumnSix = columns[6], ColumnSeven = columns[7], ColumnEight = columns[8], ColumnNine = columns[9], ColumnTen = columns[10], ColumnEleven = columns[11], ColumnTwelve = columns[12], ColumnThirteen = columns[13], ColumnFourteen = columns[14], ColumnFifteen = columns[15], ColumnSixteen = columns[16], ColumnSeventeen = columns[17] }; }
- 通过创建新对象实例化 58 个对象
总时间:868 纳秒
while (reader2.Read()) { string[] columns = reader2.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { ColumnZero = columns[0], ColumnOne = columns[1], ColumnTwo = columns[2], ColumnThree = columns[3], ColumnFour = columns[4], ColumnFive = columns[5], ColumnSix = columns[6], ColumnSeven = columns[7], ColumnEight = columns[8], ColumnNine = columns[9], ColumnTen = columns[10], ColumnEleven = columns[11], ColumnTwelve = columns[12], ColumnThirteen = columns[13], ColumnFourteen = columns[14], ColumnFifteen = columns[15], ColumnSixteen = columns[16], ColumnSeventeen = columns[17] }; }
Albeit, not completely fair since the reflection also has to retrieve a specific attribute of every property 58*18 times on top of creating a new object via reflection, but it at least provides some perspective.
尽管这并不完全公平,因为在通过反射创建新对象的基础上,反射还必须检索每个属性的特定属性 58*18 次,但它至少提供了一些视角。