Skip to content

Commit 2928b87

Browse files
Merge pull request #3 from servicetitan/build-proxy-non-generic
Add BuildLazyProxyType non-generic overload
2 parents d9f1501 + 49f380c commit 2928b87

File tree

1 file changed

+38
-23
lines changed

1 file changed

+38
-23
lines changed

LazyProxy/LazyProxyBuilder.cs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,32 @@ public static class LazyProxyBuilder
2727

2828
/// <summary>
2929
/// Defines at runtime a class that implements interface T
30-
/// and proxis all invocations to <see cref="Lazy{T}"/> of this interface.
30+
/// and proxies all invocations to <see cref="Lazy{T}"/> of this interface.
3131
/// </summary>
3232
/// <typeparam name="T">The interface proxy type implements.</typeparam>
3333
/// <returns>The lazy proxy type.</returns>
3434
public static Type BuildLazyProxyType<T>()
35+
{
36+
return BuildLazyProxyType(typeof(T));
37+
}
38+
39+
/// <summary>
40+
/// Defines at runtime a class that implements interface of Type
41+
/// and proxies all invocations to <see cref="Lazy{T}"/> of this interface.
42+
/// </summary>
43+
/// <param name="type">The interface proxy type implements.</param>
44+
/// <returns>The lazy proxy type.</returns>
45+
public static Type BuildLazyProxyType(Type type)
3546
{
3647
// There is no way to constraint it on the compilation step.
37-
if (!typeof(T).IsInterface)
48+
if (!type.IsInterface)
3849
{
3950
throw new NotSupportedException("The lazy proxy is supported only for interfaces.");
4051
}
4152

4253
// Lazy is used to guarantee the valueFactory is invoked only once.
4354
// More info: http://reedcopsey.com/2011/01/16/concurrentdictionarytkeytvalue-used-with-lazyt/
44-
var lazy = ProxyTypes.GetOrAdd(typeof(T), type => new Lazy<Type>(DefineProxyType<T>));
55+
var lazy = ProxyTypes.GetOrAdd(type, t => new Lazy<Type>(() => DefineProxyType(t)));
4556
return lazy.Value;
4657
}
4758

@@ -82,41 +93,45 @@ public static T CreateLazyProxyInstance<T>(Func<T> valueFactory)
8293
/// </summary>
8394
/// <typeparam name="T">The interface proxy type implements.</typeparam>
8495
/// <returns>The lazy proxy type.</returns>
85-
private static Type DefineProxyType<T>()
96+
private static Type DefineProxyType(Type type)
8697
{
8798
// Add a guid to avoid problems with defining generic types with different type parameters.
8899
// Dashes are allowed by IL but they are removed to match the class names in C#.
89100
var guid = Guid.NewGuid().ToString().Replace("-", "");
90101

91-
var type = typeof(T);
92102
var typeName = $"{type.Namespace}.{LazyProxyTypeSuffix}_{guid}_{type.Name}";
93103

94104
return ModuleBuilder.DefineType(typeName, TypeAttributes.Public)
95-
.AddInterfaceImplementation<T>()
96-
.AddServiceField<T>(out var serviceField)
97-
.AddConstructor<T>(serviceField)
98-
.AddMethods<T>(serviceField)
105+
.AddInterface(type)
106+
.AddServiceField(type, out var serviceField)
107+
.AddConstructor(type, serviceField)
108+
.AddMethods(type, serviceField)
99109
.CreateTypeInfo();
100110
}
101111

102-
private static TypeBuilder AddInterfaceImplementation<T>(this TypeBuilder typeBuilder)
112+
private static TypeBuilder AddInterface(this TypeBuilder typeBuilder, Type type)
103113
{
104-
typeBuilder.AddInterfaceImplementation(typeof(T));
114+
typeBuilder.AddInterfaceImplementation(type);
105115
return typeBuilder;
106116
}
107117

108-
private static TypeBuilder AddServiceField<T>(this TypeBuilder typeBuilder, out FieldInfo serviceField)
118+
private static TypeBuilder AddServiceField(this TypeBuilder typeBuilder,
119+
Type type, out FieldInfo serviceField)
109120
{
110-
serviceField = typeBuilder.DefineField(ServiceFieldName, typeof(Lazy<T>), FieldAttributes.Private);
121+
serviceField = typeBuilder.DefineField(
122+
ServiceFieldName,
123+
typeof(Lazy<>).MakeGenericType(type),
124+
FieldAttributes.Private);
125+
111126
return typeBuilder;
112127
}
113128

114-
private static TypeBuilder AddConstructor<T>(this TypeBuilder typeBuilder, FieldInfo serviceField)
129+
private static TypeBuilder AddConstructor(this TypeBuilder typeBuilder, Type type, FieldInfo serviceField)
115130
{
116131
var constructorBuilder = typeBuilder.DefineConstructor(
117132
MethodAttributes.Public,
118133
CallingConventions.Standard,
119-
new[] {typeof(Lazy<T>)}
134+
new[] {typeof(Lazy<>).MakeGenericType(type)}
120135
);
121136

122137
var generator = constructorBuilder.GetILGenerator();
@@ -129,10 +144,10 @@ private static TypeBuilder AddConstructor<T>(this TypeBuilder typeBuilder, Field
129144
return typeBuilder;
130145
}
131146

132-
private static TypeBuilder AddMethods<T>(this TypeBuilder typeBuilder, FieldInfo serviceField)
147+
private static TypeBuilder AddMethods(this TypeBuilder typeBuilder, Type type, FieldInfo serviceField)
133148
{
134-
var methods = GetMethods<T>();
135-
var getServiceValueMethod = GetGetServiceValueMethod<T>(serviceField);
149+
var methods = GetMethods(type);
150+
var getServiceValueMethod = GetGetServiceValueMethod(serviceField);
136151

137152
foreach (var method in methods)
138153
{
@@ -176,20 +191,20 @@ private static TypeBuilder AddMethods<T>(this TypeBuilder typeBuilder, FieldInfo
176191
return typeBuilder;
177192
}
178193

179-
private static IEnumerable<MethodInfo> GetMethods<T>()
194+
private static IEnumerable<MethodInfo> GetMethods(Type type)
180195
{
181196
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
182197

183-
return typeof(T).GetMethods(flags)
184-
.Concat(typeof(T).GetInterfaces()
198+
return type.GetMethods(flags)
199+
.Concat(type.GetInterfaces()
185200
.SelectMany(@interface => @interface.GetMethods(flags)))
186201
.Distinct();
187202
}
188203

189-
private static MethodInfo GetGetServiceValueMethod<T>(FieldInfo serviceField)
204+
private static MethodInfo GetGetServiceValueMethod(FieldInfo serviceField)
190205
{
191206
// ReSharper disable once PossibleNullReferenceException
192-
return serviceField.FieldType.GetProperty(nameof(Lazy<T>.Value)).GetGetMethod(true);
207+
return serviceField.FieldType.GetProperty("Value").GetGetMethod(true);
193208
}
194209
}
195210
}

0 commit comments

Comments
 (0)