Skip to content

Commit de1a3c4

Browse files
authored
Merge pull request #572 from stakx/dp/refactor/members-collector
Share `CompositeTypeContributor`'s type element collections with `MembersCollector`
2 parents c2649e3 + 9902dc2 commit de1a3c4

9 files changed

+169
-154
lines changed

src/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,15 @@ public ClassProxyTargetContributor(Type targetType, INamingScope namingScope)
3737
this.targetType = targetType;
3838
}
3939

40-
protected override IEnumerable<MembersCollector> CollectElementsToProxyInternal(IProxyGenerationHook hook)
40+
protected override IEnumerable<MembersCollector> GetCollectors()
4141
{
42-
Debug.Assert(hook != null, "hook != null");
43-
4442
var targetItem = new ClassMembersCollector(targetType) { Logger = Logger };
45-
targetItem.CollectMembersToProxy(hook);
4643
yield return targetItem;
4744

4845
foreach (var @interface in interfaces)
4946
{
5047
var item = new InterfaceMembersOnClassCollector(@interface, true,
5148
targetType.GetInterfaceMap(@interface)) { Logger = Logger };
52-
item.CollectMembersToProxy(hook);
5349
yield return item;
5450
}
5551
}

src/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,15 @@ public ClassProxyWithTargetTargetContributor(Type targetType, INamingScope namin
3535
this.targetType = targetType;
3636
}
3737

38-
protected override IEnumerable<MembersCollector> CollectElementsToProxyInternal(IProxyGenerationHook hook)
38+
protected override IEnumerable<MembersCollector> GetCollectors()
3939
{
40-
Debug.Assert(hook != null, "hook != null");
41-
4240
var targetItem = new WrappedClassMembersCollector(targetType) { Logger = Logger };
43-
targetItem.CollectMembersToProxy(hook);
4441
yield return targetItem;
4542

4643
foreach (var @interface in interfaces)
4744
{
4845
var item = new InterfaceMembersOnClassCollector(@interface, true,
4946
targetType.GetInterfaceMap(@interface)) { Logger = Logger };
50-
item.CollectMembersToProxy(hook);
5147
yield return item;
5248
}
5349
}

src/Castle.Core/DynamicProxy/Contributors/CompositeTypeContributor.cs

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ internal abstract class CompositeTypeContributor : ITypeContributor
3131
protected readonly ICollection<Type> interfaces = new HashSet<Type>();
3232

3333
private ILogger logger = NullLogger.Instance;
34-
private readonly ICollection<MetaProperty> properties = new TypeElementCollection<MetaProperty>();
35-
private readonly ICollection<MetaEvent> events = new TypeElementCollection<MetaEvent>();
36-
private readonly ICollection<MetaMethod> methods = new TypeElementCollection<MetaMethod>();
34+
private readonly List<MetaProperty> properties = new List<MetaProperty>();
35+
private readonly List<MetaEvent> events = new List<MetaEvent>();
36+
private readonly List<MetaMethod> methods = new List<MetaMethod>();
3737

3838
protected CompositeTypeContributor(INamingScope namingScope)
3939
{
@@ -48,27 +48,18 @@ public ILogger Logger
4848

4949
public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model)
5050
{
51-
foreach (var collector in CollectElementsToProxyInternal(hook))
51+
Debug.Assert(hook != null);
52+
Debug.Assert(model != null);
53+
54+
var sink = new MembersCollectorSink(model, this);
55+
56+
foreach (var collector in GetCollectors())
5257
{
53-
foreach (var method in collector.Methods)
54-
{
55-
model.AddMethod(method);
56-
methods.Add(method);
57-
}
58-
foreach (var @event in collector.Events)
59-
{
60-
model.AddEvent(@event);
61-
events.Add(@event);
62-
}
63-
foreach (var property in collector.Properties)
64-
{
65-
model.AddProperty(property);
66-
properties.Add(property);
67-
}
58+
collector.CollectMembersToProxy(hook, sink);
6859
}
6960
}
7061

71-
protected abstract IEnumerable<MembersCollector> CollectElementsToProxyInternal(IProxyGenerationHook hook);
62+
protected abstract IEnumerable<MembersCollector> GetCollectors();
7263

7364
public virtual void Generate(ClassEmitter @class)
7465
{
@@ -145,5 +136,49 @@ private void ImplementMethod(MetaMethod method, ClassEmitter @class,
145136
}
146137
}
147138
}
139+
140+
private sealed class MembersCollectorSink : IMembersCollectorSink
141+
{
142+
private readonly MetaType model;
143+
private readonly CompositeTypeContributor contributor;
144+
145+
public MembersCollectorSink(MetaType model, CompositeTypeContributor contributor)
146+
{
147+
this.model = model;
148+
this.contributor = contributor;
149+
}
150+
151+
// You may have noticed that most contributors do not query `MetaType` at all,
152+
// but only their own collections. So perhaps you are wondering why collected
153+
// type elements are added to `model` at all, and not just to `contributor`?
154+
//
155+
// TL;DR: This prevents member name collisions in the generated proxy type.
156+
//
157+
// `MetaType` uses `TypeElementCollection`s internally, which switches members
158+
// to explicit implementation whenever a name collision with a previously added
159+
// member occurs.
160+
//
161+
// It would be pointless to do this at the level of the individual contributor,
162+
// because name collisions could still occur across several contributors. This
163+
// is why they all share the same `MetaType` instance.
164+
165+
public void Add(MetaEvent @event)
166+
{
167+
model.AddEvent(@event);
168+
contributor.events.Add(@event);
169+
}
170+
171+
public void Add(MetaMethod method)
172+
{
173+
model.AddMethod(method);
174+
contributor.methods.Add(method);
175+
}
176+
177+
public void Add(MetaProperty property)
178+
{
179+
model.AddProperty(property);
180+
contributor.properties.Add(property);
181+
}
182+
}
148183
}
149184
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2004-2021 Castle Project - http://www.castleproject.org/
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace Castle.DynamicProxy.Contributors
16+
{
17+
using Castle.DynamicProxy.Generators;
18+
19+
internal interface IMembersCollectorSink
20+
{
21+
void Add(MetaEvent @event);
22+
void Add(MetaMethod method);
23+
void Add(MetaProperty property);
24+
}
25+
}

src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,12 @@ public InterfaceProxyTargetContributor(Type proxyTargetType, bool canChangeTarge
3434
this.canChangeTarget = canChangeTarget;
3535
}
3636

37-
protected override IEnumerable<MembersCollector> CollectElementsToProxyInternal(IProxyGenerationHook hook)
37+
protected override IEnumerable<MembersCollector> GetCollectors()
3838
{
39-
Debug.Assert(hook != null, "hook != null");
40-
4139
foreach (var @interface in interfaces)
4240
{
4341
var item = GetCollectorForInterface(@interface);
4442
item.Logger = Logger;
45-
item.CollectMembersToProxy(hook);
4643
yield return item;
4744
}
4845
}

src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,11 @@ public InterfaceProxyWithoutTargetContributor(INamingScope namingScope, GetTarge
3232
getTargetExpression = getTarget;
3333
}
3434

35-
protected override IEnumerable<MembersCollector> CollectElementsToProxyInternal(IProxyGenerationHook hook)
35+
protected override IEnumerable<MembersCollector> GetCollectors()
3636
{
37-
Debug.Assert(hook != null, "hook != null");
3837
foreach (var @interface in interfaces)
3938
{
4039
var item = new InterfaceMembersCollector(@interface);
41-
item.CollectMembersToProxy(hook);
4240
yield return item;
4341
}
4442
}

0 commit comments

Comments
 (0)