Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nullable reference type annotations to DynamicProxy's public API #668

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,7 @@
Enhancements:
- Two new generic method overloads `proxyGenerator.CreateClassProxy<TClass>([options], constructorArguments, interceptors)` (@backstromjoel, #636)
- Allow specifying which attributes should always be copied to proxy class by adding attribute type to `AttributesToAlwaysReplicate`. Previously only non-inherited, with `Inherited=false`, attributes were copied. (@shoaibshakeel381, #633)
- DynamicProxy's public API has been augmented with nullable reference type annotations (@stakx, #668)

Bugfixes:
- `ArgumentException`: "Could not find method overriding method" with overridden class method having generic by-ref parameter (@stakx, #657)
Expand Down
257 changes: 129 additions & 128 deletions ref/Castle.Core-net462.cs

Large diffs are not rendered by default.

248 changes: 125 additions & 123 deletions ref/Castle.Core-net6.0.cs

Large diffs are not rendered by default.

247 changes: 124 additions & 123 deletions ref/Castle.Core-netstandard2.0.cs

Large diffs are not rendered by default.

247 changes: 124 additions & 123 deletions ref/Castle.Core-netstandard2.1.cs

Large diffs are not rendered by default.

31 changes: 17 additions & 14 deletions src/Castle.Core/DynamicProxy/AbstractInvocation.cs
Expand Up @@ -12,28 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#nullable enable

namespace Castle.DynamicProxy
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

public abstract class AbstractInvocation : IInvocation
{
private readonly IInterceptor[] interceptors;
private readonly object[] arguments;
private readonly object?[] arguments;
private int currentInterceptorIndex = -1;
private Type[] genericMethodArguments;
private Type[]? genericMethodArguments;
private readonly MethodInfo proxiedMethod;
protected readonly object proxyObject;

protected AbstractInvocation(
object proxy,
IInterceptor[] interceptors,
MethodInfo proxiedMethod,
object[] arguments)
object?[] arguments)
{
Debug.Assert(proxiedMethod != null);
proxyObject = proxy;
this.interceptors = interceptors;
this.proxiedMethod = proxiedMethod;
Expand All @@ -45,13 +47,13 @@ public void SetGenericMethodArguments(Type[] arguments)
genericMethodArguments = arguments;
}

public abstract object InvocationTarget { get; }
public abstract object? InvocationTarget { get; }

public abstract Type TargetType { get; }
public abstract Type? TargetType { get; }

public abstract MethodInfo MethodInvocationTarget { get; }
public abstract MethodInfo? MethodInvocationTarget { get; }

public Type[] GenericArguments
public Type[]? GenericArguments
{
get { return genericMethodArguments; }
}
Expand All @@ -71,7 +73,7 @@ public MethodInfo GetConcreteMethod()
return EnsureClosedMethod(Method);
}

public MethodInfo GetConcreteMethodInvocationTarget()
public MethodInfo? GetConcreteMethodInvocationTarget()
{
// it is ensured by the InvocationHelper that method will be closed
var method = MethodInvocationTarget;
Expand All @@ -80,19 +82,19 @@ public MethodInfo GetConcreteMethodInvocationTarget()
return method;
}

public object ReturnValue { get; set; }
public object? ReturnValue { get; set; }

public object[] Arguments
public object?[] Arguments
{
get { return arguments; }
}

public void SetArgumentValue(int index, object value)
public void SetArgumentValue(int index, object? value)
{
arguments[index] = value;
}

public object GetArgumentValue(int index)
public object? GetArgumentValue(int index)
{
return arguments[index];
}
Expand Down Expand Up @@ -137,6 +139,7 @@ public IInvocationProceedInfo CaptureProceedInfo()

protected abstract void InvokeMethodOnTarget();

[DoesNotReturn]
protected void ThrowOnNoTarget()
{
// let's try to build as friendly message as we can
Expand All @@ -152,7 +155,7 @@ protected void ThrowOnNoTarget()

string methodKindIs;
string methodKindDescription;
if (Method.DeclaringType.IsClass && Method.IsAbstract)
if (Method.DeclaringType!.IsClass && Method.IsAbstract)
{
methodKindIs = "is abstract";
methodKindDescription = "an abstract method";
Expand Down
6 changes: 4 additions & 2 deletions src/Castle.Core/DynamicProxy/AllMethodsHook.cs
Expand Up @@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#nullable enable

namespace Castle.DynamicProxy
{
using System;
Expand All @@ -32,7 +34,7 @@ public class AllMethodsHook : IProxyGenerationHook

public virtual bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
return SkippedTypes.Contains(methodInfo.DeclaringType) == false;
return SkippedTypes.Contains(methodInfo.DeclaringType!) == false;
}

public virtual void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
Expand All @@ -43,7 +45,7 @@ public virtual void MethodsInspected()
{
}

public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj != null && obj.GetType() == GetType();
}
Expand Down
80 changes: 41 additions & 39 deletions src/Castle.Core/DynamicProxy/CustomAttributeInfo.cs
Expand Up @@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#nullable enable

namespace Castle.DynamicProxy
{
using System;
Expand All @@ -34,26 +36,26 @@ public class CustomAttributeInfo : IEquatable<CustomAttributeInfo>
// Cached empty arrays to avoid unnecessary allocations
private static readonly PropertyInfo[] EmptyProperties = new PropertyInfo[0];
private static readonly FieldInfo[] EmptyFields = new FieldInfo[0];
private static readonly object[] EmptyValues = new object[0];
private static readonly object?[] EmptyValues = new object?[0];

private static readonly IEqualityComparer<object> ValueComparer = new AttributeArgumentValueEqualityComparer();
private static readonly AttributeArgumentValueEqualityComparer ValueComparer = new AttributeArgumentValueEqualityComparer();

private readonly CustomAttributeBuilder builder;
private readonly ConstructorInfo constructor;
private readonly object[] constructorArgs;
private readonly IDictionary<string, object> properties;
private readonly IDictionary<string, object> fields;
private readonly object?[] constructorArgs;
private readonly IDictionary<string, object?> properties;
private readonly IDictionary<string, object?> fields;

public CustomAttributeInfo(
ConstructorInfo constructor,
object[] constructorArgs,
object?[] constructorArgs,
PropertyInfo[] namedProperties,
object[] propertyValues,
object?[] propertyValues,
FieldInfo[] namedFields,
object[] fieldValues)
object?[] fieldValues)
{
// Will take care of validating the arguments
this.builder = new CustomAttributeBuilder(constructor, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues);
this.builder = new CustomAttributeBuilder(constructor, constructorArgs, namedProperties, propertyValues!, namedFields, fieldValues!);
stakx marked this conversation as resolved.
Show resolved Hide resolved

this.constructor = constructor;
this.constructorArgs = constructorArgs.Length == 0 ? EmptyValues : constructorArgs.ToArray();
Expand All @@ -63,35 +65,35 @@ public class CustomAttributeInfo : IEquatable<CustomAttributeInfo>

public CustomAttributeInfo(
ConstructorInfo constructor,
object[] constructorArgs,
object?[] constructorArgs,
PropertyInfo[] namedProperties,
object[] propertyValues)
object?[] propertyValues)
: this(constructor, constructorArgs, namedProperties, propertyValues, EmptyFields, EmptyValues)
{
}

public CustomAttributeInfo(
ConstructorInfo constructor,
object[] constructorArgs,
object?[] constructorArgs,
FieldInfo[] namedFields,
object[] fieldValues)
object?[] fieldValues)
: this(constructor, constructorArgs, EmptyProperties, EmptyValues, namedFields, fieldValues)
{
}

public CustomAttributeInfo(
ConstructorInfo constructor,
object[] constructorArgs)
object?[] constructorArgs)
: this(constructor, constructorArgs, EmptyProperties, EmptyValues, EmptyFields, EmptyValues)
{
}

public static CustomAttributeInfo FromExpression(Expression<Func<Attribute>> expression)
{
var namedProperties = new List<PropertyInfo>();
var propertyValues = new List<object>();
var propertyValues = new List<object?>();
var namedFields = new List<FieldInfo>();
var fieldValues = new List<object>();
var fieldValues = new List<object?>();

var body = UnwrapBody(expression.Body);

Expand All @@ -114,7 +116,7 @@ public static CustomAttributeInfo FromExpression(Expression<Func<Attribute>> exp
throw new ArgumentException("Only assignment bindings are supported");
}

object value = GetAttributeArgumentValue(assignment.Expression, allowArray: true);
object? value = GetAttributeArgumentValue(assignment.Expression, allowArray: true);

var property = assignment.Member as PropertyInfo;
if (property != null)
Expand All @@ -138,15 +140,15 @@ public static CustomAttributeInfo FromExpression(Expression<Func<Attribute>> exp
}
}

var ctorArguments = new List<object>();
var ctorArguments = new List<object?>();
foreach (var arg in newExpression.Arguments)
{
object value = GetAttributeArgumentValue(arg, allowArray: true);
object? value = GetAttributeArgumentValue(arg, allowArray: true);
ctorArguments.Add(value);
}

return new CustomAttributeInfo(
newExpression.Constructor,
newExpression.Constructor!,
ctorArguments.ToArray(),
namedProperties.ToArray(),
propertyValues.ToArray(),
Expand All @@ -168,7 +170,7 @@ private static Expression UnwrapBody(Expression body)
return body;
}

private static object GetAttributeArgumentValue(Expression arg, bool allowArray)
private static object? GetAttributeArgumentValue(Expression arg, bool allowArray)
{
switch (arg.NodeType)
{
Expand All @@ -190,11 +192,11 @@ private static object GetAttributeArgumentValue(Expression arg, bool allowArray)
if (allowArray)
{
var newArrayExpr = (NewArrayExpression) arg;
var array = Array.CreateInstance(newArrayExpr.Type.GetElementType(), newArrayExpr.Expressions.Count);
var array = Array.CreateInstance(newArrayExpr.Type.GetElementType()!, newArrayExpr.Expressions.Count);
int index = 0;
foreach (var expr in newArrayExpr.Expressions)
{
object value = GetAttributeArgumentValue(expr, allowArray: false);
object? value = GetAttributeArgumentValue(expr, allowArray: false);
array.SetValue(value, index);
index++;
}
Expand All @@ -216,7 +218,7 @@ internal CustomAttributeBuilder Builder
get { return builder; }
}

public bool Equals(CustomAttributeInfo other)
public bool Equals(CustomAttributeInfo? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
Expand All @@ -226,7 +228,7 @@ public bool Equals(CustomAttributeInfo other)
AreMembersEquivalent(fields, other.fields);
}

public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
Expand All @@ -246,14 +248,14 @@ public override int GetHashCode()
}
}

private static bool AreMembersEquivalent(IDictionary<string, object> x, IDictionary<string, object> y)
private static bool AreMembersEquivalent(IDictionary<string, object?> x, IDictionary<string, object?> y)
{
if (x.Count != y.Count)
return false;

foreach (var kvp in x)
{
object value;
object? value;
if (!y.TryGetValue(kvp.Key, out value))
return false;
if (!ValueComparer.Equals(kvp.Value, value))
Expand All @@ -262,20 +264,20 @@ private static bool AreMembersEquivalent(IDictionary<string, object> x, IDiction
return true;
}

private static int CombineHashCodes(IEnumerable<object> values)
private static int CombineHashCodes(IEnumerable<object?> values)
{
unchecked
{
int hashCode = 173;
foreach (object value in values)
foreach (object? value in values)
{
hashCode = (hashCode*397) ^ ValueComparer.GetHashCode(value);
}
return hashCode;
}
}

private static int CombineMemberHashCodes(IDictionary<string, object> dict)
private static int CombineMemberHashCodes(IDictionary<string, object?> dict)
{
unchecked
{
Expand All @@ -293,20 +295,20 @@ private static int CombineMemberHashCodes(IDictionary<string, object> dict)
}
}

private IDictionary<string, object> MakeNameValueDictionary<T>(T[] members, object[] values)
private IDictionary<string, object?> MakeNameValueDictionary<T>(T[] members, object?[] values)
where T : MemberInfo
{
var dict = new Dictionary<string, object>();
var dict = new Dictionary<string, object?>();
for (int i = 0; i < members.Length; i++)
{
dict.Add(members[i].Name, values[i]);
}
return dict;
}

private class AttributeArgumentValueEqualityComparer : IEqualityComparer<object>
private class AttributeArgumentValueEqualityComparer : IEqualityComparer<object?>
{
bool IEqualityComparer<object>.Equals(object x, object y)
new public bool Equals(object? x, object? y)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need the new keyword?

{
if (ReferenceEquals(x, y))
return true;
Expand All @@ -323,7 +325,7 @@ bool IEqualityComparer<object>.Equals(object x, object y)
return x.Equals(y);
}

int IEqualityComparer<object>.GetHashCode(object obj)
public int GetHashCode(object? obj)
{
if (obj == null)
return 0;
Expand All @@ -334,13 +336,13 @@ int IEqualityComparer<object>.GetHashCode(object obj)
return obj.GetHashCode();
}

private static IEnumerable<object> AsObjectEnumerable(object array)
private static IEnumerable<object?> AsObjectEnumerable(object array)
{
// Covariance doesn't work for value types
if (array.GetType().GetElementType().IsValueType)
return ((Array)array).Cast<object>();
if (array.GetType().GetElementType()!.IsValueType)
return ((Array)array).Cast<object?>();

return (IEnumerable<object>)array;
return (IEnumerable<object?>)array;
}
}
}
Expand Down