I have a Func property on my class as below.
public class ClassA {
public Func<string, IClassB> MyProperty { get; set; }
}
Checking MyProperty for null is not possible. Therefore my question is if it it possible to verify that MyProperty has been initialized in some way?
EDIT: I wasn't giving you my whole picture because i beleived it was exactly the same for Func in general. Sorry for that.
Thing is that I am actually instantiating the property using reflection and ahead of this I pick up the value of MyProperty to set it only when it is not instantiated.
...
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (Attribute.IsDefined(property,typeof(WireAttribute)))
{
var propertyValue = property.GetValue(objectToWire, null);
if (propertyValue == null) //<-- THIS IS NOT TRUE FOR FUNC RETURN TYPES
...
For regular properties, not Func return type it works as expected.
ClassA clsA = new ClassA();
if (clsA.MyProperty == null)
MessageBox.Show("IsNull");
clsA.MyProperty = new Func<string, bool>(x => x.Equals("1"));
MessageBox.Show(clsA.MyProperty == null ? "IsNull" : "IsNotNull");
this works very good
If I take your code and do
var a = new ClassA();
var initialized = a.MyProperty == null;
the code is perfectly valid. Therefore your assertion is incorrect, checking for null is possible.
What are you trying to achieve, perhaps you want something like.
public class ClassA
{
private readonly Func<string, IClassB> myFunc;
public ClassA(Func<string, IClassB> myFunc)
{
this.myFunc = myFunc;
}
public IClassB MyFunc(string input)
{
if (this.myFunc = null)
{
return null;
}
return this.myFunc(input);
}
}
At runtime, you can check if the property has been initialized. What you can't check is the value returned by it's invocation, as the invocation is dynamic.
class Program
{
interface IClassB { }
class ClassB1 : IClassB { }
class ClassB2 : IClassB { }
class ClassA
{
public Func<string, IClassB>
MyProperty { get; set; }
}
static void Main(string[] args)
{
var classA = new ClassA();
Console.WriteLine((classA.MyProperty == null)
? "Not initialized" : "Initialized");
classA.MyProperty = (a) =>
{
if (a == "1")
return new ClassB1();
else if (a == "2")
return new ClassB2();
else
return null;
};
Console.WriteLine((classA.MyProperty == null)
? "Not initialized" : "Initialized");
object
c1 = classA.MyProperty.Invoke("1"),
c2 = classA.MyProperty.Invoke("2"),
c3 = classA.MyProperty.Invoke("3");
Console.WriteLine((c1 != null) ? c1.GetType().Name : "null");
Console.WriteLine((c2 != null) ? c2.GetType().Name : "null");
Console.WriteLine((c3 != null) ? c3.GetType().Name : "null");
}
}
Apart from the other answers, you may use a property for the Func (if you want/can to test this inside ClassA):
public class ClassA {
private Func<string, IClassB> myProperty;
public Func<string, IClassB> MyProperty {
get {
if (myProperty == null)
return some default behaviour;
return myProperty;
}
set {
myProperty = value;
}
}
You can check it by standard means, like this:
IClassB a = new IClassB();
//it is null now so Empty will follow
if (a.MyProperty == null) Console.WriteLine("Empty");
else Console.WriteLine("Not empty");
a.MyProperty = new Func<string, IClassB>((s)=>{ return new IClassB(); });
//it is not null now so Not empty will follow
if (a == null) Console.WriteLine("Empty");
else Console.WriteLine("Not empty");
Related
C# 8.0 introduces nullable reference types. Here's a simple class with a nullable property:
public class Foo
{
public String? Bar { get; set; }
}
Is there a way to check a class property uses a nullable reference type via reflection?
In .NET 6, the NullabilityInfoContext APIs were added to handle this. See this answer.
Prior to this, you need to read the attributes yourself. This appears to work, at least on the types I've tested it with.
public static bool IsNullable(PropertyInfo property) =>
IsNullableHelper(property.PropertyType, property.DeclaringType, property.CustomAttributes);
public static bool IsNullable(FieldInfo field) =>
IsNullableHelper(field.FieldType, field.DeclaringType, field.CustomAttributes);
public static bool IsNullable(ParameterInfo parameter) =>
IsNullableHelper(parameter.ParameterType, parameter.Member, parameter.CustomAttributes);
private static bool IsNullableHelper(Type memberType, MemberInfo? declaringType, IEnumerable<CustomAttributeData> customAttributes)
{
if (memberType.IsValueType)
return Nullable.GetUnderlyingType(memberType) != null;
var nullable = customAttributes
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
if (nullable != null && nullable.ConstructorArguments.Count == 1)
{
var attributeArgument = nullable.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte[]))
{
var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value!;
if (args.Count > 0 && args[0].ArgumentType == typeof(byte))
{
return (byte)args[0].Value! == 2;
}
}
else if (attributeArgument.ArgumentType == typeof(byte))
{
return (byte)attributeArgument.Value! == 2;
}
}
for (var type = declaringType; type != null; type = type.DeclaringType)
{
var context = type.CustomAttributes
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
if (context != null &&
context.ConstructorArguments.Count == 1 &&
context.ConstructorArguments[0].ArgumentType == typeof(byte))
{
return (byte)context.ConstructorArguments[0].Value! == 2;
}
}
// Couldn't find a suitable attribute
return false;
}
See this document for details.
The general gist is that either the property itself can have a [Nullable] attribute on it, or if it doesn't the enclosing type might have [NullableContext] attribute. We first look for [Nullable], then if we don't find it we look for [NullableContext] on the enclosing type.
The compiler might embed the attributes into the assembly, and since we might be looking at a type from a different assembly, we need to do a reflection-only load.
[Nullable] might be instantiated with an array, if the property is generic. In this case, the first element represents the actual property (and further elements represent generic arguments). [NullableContext] is always instantiated with a single byte.
A value of 2 means "nullable". 1 means "not nullable", and 0 means "oblivious".
.NET 6 Preview 7 adds reflection APIs to get nullability info.
Libraries: Reflection APIs for nullability information
Obviously, this only helps folks targeting .NET 6+.
Getting top-level nullability information
Imagine you’re implementing a serializer. Using these new APIs the serializer can check whether a given property can be set to null:
private NullabilityInfoContext _nullabilityContext = new NullabilityInfoContext();
private void DeserializePropertyValue(PropertyInfo p, object instance, object? value)
{
if (value is null)
{
var nullabilityInfo = _nullabilityContext.Create(p);
if (nullabilityInfo.WriteState is not NullabilityState.Nullable)
{
throw new MySerializerException($"Property '{p.GetType().Name}.{p.Name}'' cannot be set to null.");
}
}
p.SetValue(instance, value);
}
I wrote a library to do reflection of NRT types - internally it looks at the generated attributes and gives you a simple API:
https://github.com/RicoSuter/Namotion.Reflection
Late answer.
This is what I ended up using thanks to Bill Menees:
static bool IsMarkedAsNullable(PropertyInfo p)
{
return new NullabilityInfoContext().Create(p).WriteState is NullabilityState.Nullable;
}
// Tests:
class Foo
{
public int Int1 { get; set; }
public int? Int2 { get; set; } = null;
public string Str1 { get; set; } = "";
public string? Str2 { get; set; } = null;
public List<Foo> Lst1 { get; set; } = new();
public List<Foo>? Lst2 { get; set; } = null;
public Dictionary<int, object> Dic1 { get; set; } = new();
public Dictionary<int, object>? Dic2 { get; set; } = null;
}
....
var props = typeof(Foo).GetProperties();
foreach(var prop in props)
{
Console.WriteLine($"Prop:{prop.Name} IsNullable:{IsMarkedAsNullable(prop)}");
}
// outputs:
Prop:Int1 IsNullable:False
Prop:Int2 IsNullable:True
Prop:Str1 IsNullable:False
Prop:Str2 IsNullable:True
Prop:Lst1 IsNullable:False
Prop:Lst2 IsNullable:True
Prop:Dic1 IsNullable:False
Prop:Dic2 IsNullable:True
A great answer there by #rico-suter !
The following is for those who just want a quick cut-and-paste solution until the real McCoy is available (see the proposal https://github.com/dotnet/runtime/issues/29723 ).
I put this together based on #canton7's post above plus a short look at the ideas in #rico-suter's code. The change from the #canton7's code is just abstracting the list of attribute sources and including a few new ones.
private static bool IsAttributedAsNonNullable(this PropertyInfo propertyInfo)
{
return IsAttributedAsNonNullable(
new dynamic?[] { propertyInfo },
new dynamic?[] { propertyInfo.DeclaringType, propertyInfo.DeclaringType?.DeclaringType, propertyInfo.DeclaringType?.GetTypeInfo() }
);
}
private static bool IsAttributedAsNonNullable(this ParameterInfo parameterInfo)
{
return IsAttributedAsNonNullable(
new dynamic?[] { parameterInfo },
new dynamic?[] { parameterInfo.Member, parameterInfo.Member.DeclaringType, parameterInfo.Member.DeclaringType?.DeclaringType, parameterInfo.Member.DeclaringType?.GetTypeInfo()
);
}
private static bool IsAttributedAsNonNullable( dynamic?[] nullableAttributeSources, dynamic?[] nullableContextAttributeSources)
{
foreach (dynamic? nullableAttributeSource in nullableAttributeSources) {
if (nullableAttributeSource == null) { continue; }
CustomAttributeData? nullableAttribute = ((IEnumerable<CustomAttributeData>)nullableAttributeSource.CustomAttributes).FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
if (nullableAttribute != null && nullableAttribute.ConstructorArguments.Count == 1) {
CustomAttributeTypedArgument attributeArgument = nullableAttribute.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte[])) {
var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)(attributeArgument.Value ?? throw new NullReferenceException("Logic error!"));
if (args.Count > 0 && args[0].ArgumentType == typeof(byte)) {
byte value = (byte)(args[0].Value ?? throw new NullabilityLogicException());
return value == 1; // 0 = oblivious, 1 = nonnullable, 2 = nullable
}
} else if (attributeArgument.ArgumentType == typeof(byte)) {
byte value = (byte)(attributeArgument.Value ?? throw new NullReferenceException("Logic error!"));
return value == 1; // 0 = oblivious, 1 = nonnullable, 2 = nullable
} else {
throw new InvalidOperationException($"Unrecognized argument type for NullableAttribute.");
}
}
}
foreach (dynamic? nullableContextAttributeSource in nullableContextAttributeSources) {
if (nullableContextAttributeSource == null) { continue; }
CustomAttributeData? nullableContextAttribute = ((IEnumerable<CustomAttributeData>)nullableContextAttributeSource.CustomAttributes).FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
if (nullableContextAttribute != null && nullableContextAttribute.ConstructorArguments.Count == 1) {
CustomAttributeTypedArgument attributeArgument = nullableContextAttribute.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte)) {
byte value = (byte)(nullableContextAttribute.ConstructorArguments[0].Value ?? throw new NullabilityLogicException());
return value == 1;
} else {
throw new InvalidOperationException($"Unrecognized argument type for NullableContextAttribute.");
}
}
}
return false;
}
It's only the string? which gets a bit tricky. The rest of the nullable types are pretty straightforward to find out. For strings I used the following method, which you need to pass in a PropertyInfo object taken via reflection.
private bool IsNullable(PropertyInfo prop)
{
return prop.CustomAttributes.Any(x => x.AttributeType.Name == "NullableAttribute");
}
I have created a generic method(NewIfNull) to create an instance of class if object is null. But currently I am supplying the property name as hard-coded which I don't want to do. Please help if there is any way to do this.
static void Main(string[] args)
{
RnD rnD = new RnD();
rnD.NewIfNull("A").A.NewIfNull("B").B.NewIfNull("C");
if(rnD.A.B.C != null)
{
}
}
class RnD
{
public A A { get; set; }
}
class A
{
public B B { get; set; }
}
class B
{
public C C { get; set; }
}
class C
{
}
public static class ExtensionClass1
{
public static T NewIfNull<T>(this T obj, string propName)
{
if (obj != null)
{
if (obj.GetType().GetProperty(propName) != null &&
obj.GetType().GetProperty(propName).GetValue(obj) == null)
{
Type type =
obj.GetType().GetProperty(propName).PropertyType;
if (type.IsClass)
{
var getobj = Activator.CreateInstance(type);
obj.GetType().GetProperty(propName).SetValue(obj,
getobj);
}
}
}
return obj;
}
}
I don't want to pass "A", "B" and "C" as hard-coded in below code.
rnD.NewIfNull("A").A.NewIfNull("B").B.NewIfNull("C");
A simple answer without trying to understand what you are actually trying to do is to use nameof:
rnD.NewIfNull(nameof(RnD.A)).A.NewIfNull(nameof(A.B)).B.NewIfNull(nameof(B.C));
You can use expressions to do this.
public static TProperty NewIfNull<TObj, TProperty>(this TObj obj, Expression<Func<TObj, TProperty>> selector)
{
if (!(selector.Body is MemberExpression memberExpression)
|| !(memberExpression.Member is PropertyInfo propertyInfo))
{
throw new ArgumentException("Expected a lambda in the form x => x.Property", nameof(selector));
}
var property = (TProperty)propertyInfo.GetValue(obj);
if (property == null)
{
// We already know that typeof(TProperty).IsClass is true - if it
// wasn't, then 'property' could not have been null above.
property = (TProperty)Activator.CreateInstance(typeof(TProperty));
propertyInfo.SetValue(obj, property);
}
return property;
}
Then you can call it like:
rnD.NewIfNull(x => x.A).NewIfNull(x => x.B).NewIfNull(x => x.C);
You can quite easily modify it to initialise all of your properties at the same time:
public static void NewIfNull<TObj, TProperty>(this TObj obj, Expression<Func<TObj, TProperty>> selector)
{
object subject = obj;
foreach (var member in GetMembers().Reverse())
{
if (!(member.Member is PropertyInfo propertyInfo))
{
throw new ArgumentException("Member was not a property", nameof(selector));
}
var property = propertyInfo.GetValue(subject);
if (property == null)
{
property = Activator.CreateInstance(propertyInfo.PropertyType);
propertyInfo.SetValue(subject, property);
}
subject = property;
}
IEnumerable<MemberExpression> GetMembers()
{
for (var member = GetMember(selector.Body); member != null; member = GetMember(member.Expression))
{
yield return member;
}
}
MemberExpression GetMember(Expression expr)
{
if (expr is ParameterExpression)
{
return null;
}
if (expr is MemberExpression member)
{
return member;
}
throw new ArgumentException("Expected a lambda in the form x => x.A.B.C", nameof(selector));
}
}
And call it like:
rnD.NewIfNull(x => x.A.B.C);
I have a base class:
abstract class ClassPlugin
{
public ClassPlugin(eGuiType _guyType)
{
GuiType = _guyType;
}
public eGuiType GuiType;
}
then I have various derived classes, one of them being this
class ClassIO : ClassPlugin
{
public ClassIO(eGuiType _guyType, eIoType _ioType) : base(_guyType)
{
GuyType = _guyType;
ioType = _ioType;
}
eIoType ioType;
public enum eIoType { UKNOWN, READ, WRITE, MONITOR }
public override void Action(){...}
}
so now when launching my application I use that code:
public static List<Type> FindAllDerivedTypes<T>()
{
return FindAllDerivedTypes<T>(Assembly.GetAssembly(typeof(T)));
}
public static List<Type> FindAllDerivedTypes<T>(Assembly assembly)
{
var derivedType = typeof(T);
return assembly
.GetTypes()
.Where(t =>
t != derivedType && derivedType.IsAssignableFrom(t)).ToList();
}
finally I use it with
var output = FindAllDerivedTypes<ClassPlugin>();
foreach (var classType in output)
{
if (classType.Name == "ClassIO")
{
foreach (var item in classType.GetMembers())
{
????
}
}
}
so what I need to do is [pseudocode to be put where the ??? are]
bool IsMonitorType = false;
if(item.member == eIoType && item.Value == eIoType.MONITOR)
{
IsMonitorType == true;
break;
}
and then
if(item.member.Name "Action")
{
item.member.execute();
}
so in short I have to:
identify the instance type throgh eIoType
if ioType == MONITOR execute its Action routine
Thank you for any help
if (classType.Name == "ClassIO")
{
//You can get the field like this
var fieldInfo = classType.GetField("ioType",BindingFlags.NonPublic|BindingFlags.Instance);
if (fieldInfo != null)
{
//...
}
//You can get the method like this
var methodInfo = classType.GetMethod("Action");
if (methodInfo != null)
{
//create an instance of ClassIO
var classInstance = Activator.CreateInstance(classType, new eGuiType(), ClassIO.eIoType.MONITOR);
//Execute Action method
methodInfo.Invoke(classInstance, null);
}
}
I'm not sure how you think you're going to check the value of eIoType though, you're just dealing with the Type ClassIO here not an instance of it
I have the following class:
class Foo
{
public Foo(string str, int i, bool b, DateTime d, string str2)
{
.....
}
}
I'm creating a Foo with AutoFixture:
var foo = fixture.Create<Foo>();
but I want AutoFixture to provide a known value for the str2 parameter and use the default behavior for every other parameter.
I tried implementing a SpecimenBuilder but I can't find a way to get the metadata associated with the request to know that I'm being called from the Foo constructor.
Is there any way to achieve this?
As answered here you can have something like
public class FooArg : ISpecimenBuilder
{
private readonly string value;
public FooArg(string value)
{
this.value = value;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
return new NoSpecimen(request);
if (pi.Member.DeclaringType != typeof(Foo) ||
pi.ParameterType != typeof(string) ||
pi.Name != "str2")
return new NoSpecimen(request);
return value;
}
}
and then you can register it like this
var fixture = new Fixture();
fixture.Customizations.Add(new FooArg(knownValue));
var sut = fixture.Create<Foo>();
This answers the similar problem but with custom type e.g. MyType. When given:
class Foo
{
public Foo(string str, MyType myType)
{
.....
}
}
class MyType
{
private readonly string myType;
public MyType(string myType)
{
this.myType = myType
}
}
You can call
fixture.Customize<MyType>(c => c.FromFactory(() => new MyType("myValue")));
var foo = fixture.Build<Foo>();
In my MVC3 project, I use an IUrlProvider interface to wrap the UrlHelper class. In one of my controller actions, I have a call like this:
string url = _urlProvider.Action("ValidateCode", new { code = "spam-and-eggs" });
I want to stub this method call in my unit test, which is in a separate project. The test setup looks something like this:
IUrlProvider urlProvider = MockRepository.GenerateStub<IUrlProvider>();
urlProvider.Stub(u => u.Action(
Arg<string>.Is.Equal("ValidateCode"),
Arg<object>.Is.Equal(new { code = "spam-and-eggs" }) ))
.Return("http://www.mysite.com/validate/spam-and-eggs");
Unfortunately, Arg<object>.Is.Equal(new { code = "spam-and-eggs" }) doesn't work, because new { code = "spam-and-eggs" } != new { code = "spam-and-eggs" } when the anonymous types are declared in different assemblies.
So, is there an alternative syntax I can use with Rhino Mocks to check for matching field values between anonymous objects across assemblies?
Or should I replace the anonymous object declarations with a class, like this?
public class CodeArg
{
public string code { get; set; }
public override bool Equals(object obj)
{
if(obj == null || GetType() != obj.GetType())
{
return false;
}
return code == ((CodeArg)obj).code;
}
public override int GetHashCode()
{
return code.GetHashCode();
}
}
string url = _urlProvider.Action("ValidateCode",
new CodeArg { code = "spam-and-eggs" });
IUrlProvider urlProvider = MockRepository.GenerateStub<IUrlProvider>();
urlProvider.Stub(u => u.Action(
Arg<string>.Is.Equal("ValidateCode"),
Arg<CodeArg>.Is.Equal(new CodeArg { code = "spam-and-eggs" }) ))
.Return("http://www.mysite.com/validate/spam-and-eggs");
EDIT
If my unit test was in the same project as my controller, comparing the anonymous objects would work fine. Because they are declared in separate assemblies, they will not be equal, even if they have the same field names and values. Comparing anonymous objects created by methods in different namespaces doesn't seem to be a problem.
SOLUTION
I replaced Arg<object>.Is.Equal() with Arg<object>.Matches() using a custom AbstractConstraint:
IUrlProvider urlProvider = MockRepository.GenerateStub<IUrlProvider>();
urlProvider.Stub(u => u.Action(
Arg<string>.Is.Equal("ValidateCode"),
Arg<object>.Matches(new PropertiesMatchConstraint(new { code = "spam-and-eggs" })) ))
.Return("http://www.mysite.com/validate/spam-and-eggs");
public class PropertiesMatchConstraint : AbstractConstraint
{
private readonly object _equal;
public PropertiesMatchConstraint(object obj)
{
_equal = obj;
}
public override bool Eval(object obj)
{
if (obj == null)
{
return (_equal == null);
}
var equalType = _equal.GetType();
var objType = obj.GetType();
foreach (var property in equalType.GetProperties())
{
var otherProperty = objType.GetProperty(property.Name);
if (otherProperty == null || property.GetValue(_equal, null) != otherProperty.GetValue(obj, null))
{
return false;
}
}
return true;
}
public override string Message
{
get
{
string str = _equal == null ? "null" : _equal.ToString();
return "equal to " + str;
}
}
}
Anonymous types do implement Equals and GetHashCode in a pretty normal way, calling GetHashCode and Equals for each of their submembers.
So this should pass:
Assert.AreEqual(new { code = "spam-and-eggs" },
new { code = "spam-and-eggs" });
In other words, I suspect you're looking for the problem in the wrong place.
Note that you have to specify the properties in exactly the right order - so new { a = 0, b = 1 } will not be equal to new { b = 1, a = 0 }; the two objects will be of different types.
EDIT: The anonymous type instance creation expressions have to be in the same assembly, too. This is no doubt the problem in this case.
If Equals allows you to specify an IEqualityComparer<T>, you could probably build one which is able to compare two anonymous types with the same properties by creating an instance of one type from the properties of an instance of the other, and then comparing that to the original of the same type. Of course if you were using nested anonymous types you'd need to do that recursively, which could get ugly...
As GetValue returns a boxed value, this appears to work correctly.
public class PropertiesMatchConstraint : AbstractConstraint
{
private readonly object _equal;
public PropertiesMatchConstraint(object obj)
{
_equal = obj;
}
public override bool Eval(object obj)
{
if (obj == null)
{
return (_equal == null);
}
var equalType = _equal.GetType();
var objType = obj.GetType();
foreach (var property in equalType.GetProperties())
{
var otherProperty = objType.GetProperty(property.Name);
if (otherProperty == null || !_ValuesMatch(property.GetValue(_equal, null), otherProperty.GetValue(obj, null)))
{
return false;
}
}
return true;
}
//fix for boxed conversions object:Guid != object:Guid when both values are the same guid - must call .Equals()
private bool _ValuesMatch(object value, object otherValue)
{
if (value == otherValue)
return true; //return early
if (value != null)
return value.Equals(otherValue);
return otherValue.Equals(value);
}
public override string Message
{
get
{
string str = _equal == null ? "null" : _equal.ToString();
return "equal to " + str;
}
}
}