1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 namespace Castle
.MicroKernel
18 using System
.Reflection
;
21 using Castle
.MicroKernel
.Exceptions
;
23 internal class DependencyTrackingScope
: IDisposable
25 private readonly DependencyModel dependencyTrackingKey
;
26 private DependencyModelCollection dependencies
;
28 public DependencyTrackingScope(CreationContext creationContext
, ComponentModel model
, MemberInfo info
, DependencyModel dependencyModel
)
30 if (dependencyModel
.TargetType
!= typeof (IKernel
))
32 this.dependencies
= creationContext
.Dependencies
;
34 // We track dependencies in order to detect cycled graphs
35 // This prevents a stack overflow
36 this.dependencyTrackingKey
= TrackDependency(model
, info
, dependencyModel
);
42 // if the dependency were being tracked, and we reached the dispose...
43 if (dependencies
!= null && dependencyTrackingKey
!= null)
45 // ...then the dependency was resolved successfully, we can stop tracking it.
46 UntrackDependency(dependencyTrackingKey
);
50 private DependencyModelExtended
TrackDependency(ComponentModel model
, MemberInfo info
, DependencyModel dependencyModel
)
52 DependencyModelExtended trackingKey
= new DependencyModelExtended(model
, dependencyModel
, info
);
54 if (dependencies
.Contains(trackingKey
))
56 StringBuilder sb
= new StringBuilder("A cycle was detected when trying to resolve a dependency. ");
58 sb
.Append("The dependency graph that resulted in a cycle is:");
60 foreach (DependencyModel key
in dependencies
)
62 DependencyModelExtended extendedInfo
= key
as DependencyModelExtended
;
64 if (extendedInfo
!= null)
66 sb
.AppendFormat("\r\n - {0} for {1} in type {2}",
67 key
, extendedInfo
.Info
, extendedInfo
.Info
.DeclaringType
);
71 sb
.AppendFormat("\r\n - {0}", key
);
75 sb
.AppendFormat("\r\n + {0} for {1} in {2}\r\n",
76 dependencyModel
, info
, info
.DeclaringType
);
78 throw new CircularDependencyException(sb
.ToString());
81 dependencies
.Add(trackingKey
);
86 private void UntrackDependency(DependencyModel model
)
88 dependencies
.Remove(model
);
91 #region DependencyModelExtended
94 /// Extends <see cref="DependencyModel"/> adding <see cref="MemberInfo"/> and <see cref="ComponentModel"/>
95 /// information. Th MemberInfo is only useful to provide detailed information
97 /// The ComponentModel is required so we can get resolve an object that takes as a parameter itself, but
98 /// with difference model. (See IoC 51 for the details)
101 internal class DependencyModelExtended
: DependencyModel
103 private readonly ComponentModel model
;
104 private readonly MemberInfo info
;
106 public DependencyModelExtended(ComponentModel model
, DependencyModel inner
, MemberInfo info
)
108 base(inner
.DependencyType
, inner
.DependencyKey
, inner
.TargetType
, inner
.IsOptional
)
114 public MemberInfo Info
119 public override bool Equals(object obj
)
121 DependencyModelExtended other
= obj
as DependencyModelExtended
;
124 return other
.Info
== this.Info
&&
125 other
.model
== model
&&
129 public override int GetHashCode()
131 int infoHash
= 37 ^ Info
.GetHashCode();
132 return base.GetHashCode() + infoHash
;