Skip to content

Commit 6ee5ab1

Browse files
committed
No need to store collected members in MembersCollector
A previous commit revealed that `CompositeTypeContributor` is the sole direct user of `MembersCollector`. It queries the latter's type element collections (`Events`, `Methods`, and `Properties`) only to transfer the elements somewhere else. This means that `MembersCollector` doesn't really need its own collect- ions; it could simply send collected type elements to wherever they need to go. This is done via the new interface `IMembersCollectorSink`. In principle, this also turns `CollectMembersToProxy` into a repeatable operation: `checkedMethods` no longer needs to act double duty as a flag to check whether the method was already called.
1 parent cecf7ce commit 6ee5ab1

File tree

4 files changed

+73
-57
lines changed

4 files changed

+73
-57
lines changed

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

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,13 @@ public ILogger Logger
4949
public void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model)
5050
{
5151
Debug.Assert(hook != null);
52+
Debug.Assert(model != null);
53+
54+
var sink = new MembersCollectorSink(model, this);
5255

5356
foreach (var collector in GetCollectors())
5457
{
55-
collector.CollectMembersToProxy(hook);
56-
57-
foreach (var method in collector.Methods)
58-
{
59-
model.AddMethod(method);
60-
methods.Add(method);
61-
}
62-
foreach (var @event in collector.Events)
63-
{
64-
model.AddEvent(@event);
65-
events.Add(@event);
66-
}
67-
foreach (var property in collector.Properties)
68-
{
69-
model.AddProperty(property);
70-
properties.Add(property);
71-
}
58+
collector.CollectMembersToProxy(hook, sink);
7259
}
7360
}
7461

@@ -149,5 +136,35 @@ private void ImplementMethod(MetaMethod method, ClassEmitter @class,
149136
}
150137
}
151138
}
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+
public void Add(MetaEvent @event)
152+
{
153+
model.AddEvent(@event);
154+
contributor.events.Add(@event);
155+
}
156+
157+
public void Add(MetaMethod method)
158+
{
159+
model.AddMethod(method);
160+
contributor.methods.Add(method);
161+
}
162+
163+
public void Add(MetaProperty property)
164+
{
165+
model.AddProperty(property);
166+
contributor.properties.Add(property);
167+
}
168+
}
152169
}
153170
}
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/MembersCollector.cs

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ internal abstract class MembersCollector
2828
private const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
2929
private ILogger logger = NullLogger.Instance;
3030

31-
private HashSet<MethodInfo> checkedMethods = new HashSet<MethodInfo>();
32-
private readonly List<MetaProperty> properties = new List<MetaProperty>();
33-
private readonly List<MetaEvent> events = new List<MetaEvent>();
34-
private readonly List<MetaMethod> methods = new List<MetaMethod>();
35-
3631
protected readonly Type type;
3732

3833
protected MembersCollector(Type type)
@@ -46,38 +41,17 @@ public ILogger Logger
4641
set { logger = value; }
4742
}
4843

49-
public IEnumerable<MetaMethod> Methods
50-
{
51-
get { return methods; }
52-
}
53-
54-
public IEnumerable<MetaProperty> Properties
55-
{
56-
get { return properties; }
57-
}
58-
59-
public IEnumerable<MetaEvent> Events
44+
public virtual void CollectMembersToProxy(IProxyGenerationHook hook, IMembersCollectorSink sink)
6045
{
61-
get { return events; }
62-
}
46+
var checkedMethods = new HashSet<MethodInfo>();
6347

64-
public virtual void CollectMembersToProxy(IProxyGenerationHook hook)
65-
{
66-
if (checkedMethods == null) // this method was already called!
67-
{
68-
throw new InvalidOperationException(
69-
string.Format("Can't call 'CollectMembersToProxy' method twice. This usually signifies a bug in custom {0}.",
70-
typeof(ITypeContributor)));
71-
}
7248
CollectProperties();
7349
CollectEvents();
7450
// Methods go last, because properties and events have methods too (getters/setters add/remove)
7551
// and we don't want to get duplicates, so we collect property and event methods first
7652
// then we collect methods, and add only these that aren't there yet
7753
CollectMethods();
7854

79-
checkedMethods = null; // this is ugly, should have a boolean flag for this or something
80-
8155
void CollectProperties()
8256
{
8357
var propertiesFound = type.GetProperties(Flags);
@@ -130,13 +104,13 @@ void AddProperty(PropertyInfo property)
130104
var nonInheritableAttributes = property.GetNonInheritableAttributes();
131105
var arguments = property.GetIndexParameters();
132106

133-
properties.Add(new MetaProperty(property.Name,
134-
property.PropertyType,
135-
property.DeclaringType,
136-
getter,
137-
setter,
138-
nonInheritableAttributes.Select(a => a.Builder),
139-
arguments.Select(a => a.ParameterType).ToArray()));
107+
sink.Add(new MetaProperty(property.Name,
108+
property.PropertyType,
109+
property.DeclaringType,
110+
getter,
111+
setter,
112+
nonInheritableAttributes.Select(a => a.Builder),
113+
arguments.Select(a => a.ParameterType).ToArray()));
140114
}
141115

142116
void AddEvent(EventInfo @event)
@@ -161,8 +135,8 @@ void AddEvent(EventInfo @event)
161135
return;
162136
}
163137

164-
events.Add(new MetaEvent(@event.Name,
165-
@event.DeclaringType, @event.EventHandlerType, adder, remover, EventAttributes.None));
138+
sink.Add(new MetaEvent(@event.Name,
139+
@event.DeclaringType, @event.EventHandlerType, adder, remover, EventAttributes.None));
166140
}
167141

168142
MetaMethod AddMethod(MethodInfo method, bool isStandalone)
@@ -175,7 +149,7 @@ MetaMethod AddMethod(MethodInfo method, bool isStandalone)
175149
var methodToGenerate = GetMethodToGenerate(method, hook, isStandalone);
176150
if (methodToGenerate != null)
177151
{
178-
methods.Add(methodToGenerate);
152+
sink.Add(methodToGenerate);
179153
}
180154

181155
return methodToGenerate;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ public WrappedClassMembersCollector(Type type) : base(type)
2828
{
2929
}
3030

31-
public override void CollectMembersToProxy(IProxyGenerationHook hook)
31+
public override void CollectMembersToProxy(IProxyGenerationHook hook, IMembersCollectorSink sink)
3232
{
33-
base.CollectMembersToProxy(hook);
33+
base.CollectMembersToProxy(hook, sink);
3434
CollectFields(hook);
3535
// TODO: perhaps we should also look for nested classes...
3636
}

0 commit comments

Comments
 (0)