Added testcase for generic registrations and a workaround for the CLR GetInterfaces...
[castle.git] / InversionOfControl / Castle.MicroKernel / Context / DependencyTrackingScope.cs
blob5f645697e4397840606d24cdf573820ccadac888
1 // Copyright 2004-2008 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.
15 namespace Castle.MicroKernel
17 using System;
18 using System.Reflection;
19 using System.Text;
20 using Castle.Core;
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);
40 public void Dispose()
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);
69 else
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);
83 return trackingKey;
86 private void UntrackDependency(DependencyModel model)
88 dependencies.Remove(model);
91 #region DependencyModelExtended
93 /// <summary>
94 /// Extends <see cref="DependencyModel"/> adding <see cref="MemberInfo"/> and <see cref="ComponentModel"/>
95 /// information. Th MemberInfo is only useful to provide detailed information
96 /// on exceptions.
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)
99 /// </summary>
100 [Serializable]
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)
110 this.model = model;
111 this.info = info;
114 public MemberInfo Info
116 get { return info; }
119 public override bool Equals(object obj)
121 DependencyModelExtended other = obj as DependencyModelExtended;
122 if (other == null)
123 return false;
124 return other.Info == this.Info &&
125 other.model == model &&
126 base.Equals(other);
129 public override int GetHashCode()
131 int infoHash = 37 ^ Info.GetHashCode();
132 return base.GetHashCode() + infoHash;
136 #endregion