Collection field is null when instantiating instance of the class - c#

I have a created an object that will hold errors encountered as well as a boolean field to indicate if any errors were present at all. The class looks like this.
public class ValidationResult
{
public bool IsValid{ get; set; }
public List<string> Errors { get; set; }
}
I go to use an instance of this class in a validation method as such
public class ValidationService
{
// This instance will hold the errors if there are any
ValidationResult myValidationResult = new ValidationResult();
public void ValidationMethod()
{
// Validation takes place here
...
// Some errors occurred to lets add then to the instance of the ValidationResult object
myValidationResult.IsValid = false;
myValidationResult.Errors.Add("An error occurred here are the details");
}
}
The problem is that the Errors collection in the instance myValidationResult is null? Why is this? I created an instance of the class and the boolean property IsValid is available, yet the Errors collection is null.

You must initialize your Errors property:
public class ValidationResult
{
public ValidationResult()
{
Errors = new List<string>();
}
public bool IsValid{ get { return (Errors.Count() == 0); } }
public List<string> Errors { get; set; }
}

Only value types are initialized per default. Your List<string> is a reference type and it does have it default value - null.
Look here for a little bit more information:
https://msdn.microsoft.com/en-us/library/aa691171(v=vs.71).aspx

Related

Generic throw function for non-nullable types

I am trying to convert an existing project to using nullable reference types properties using non-nullable properties during initialization.
I am using this approach for getting properties which should exist:
public class Dog
{
private Person? _person;
public int Id { get; set; }
public string Name { get; set; }
public Person Person
{
get => _person ?? throw new InvalidOperationException(
$"Unset property {nameof(_person)}. You probably forgot to Include it");
set => _person = value;
}
}
But it's tedious to write this for almost every property, so I've tried to make a generic ThrowOrGet() function:
public static class Util
{
public static T ThrowOrGet<T>([AllowNull] T obj)
{
if (obj == null)
{
throw new InvalidOperationException(
$"Unset property {nameof(obj)}. You probably forgot to Include it");
}
return obj;
}
}
Which is used like this:
public class Dog
{
private Person? _person;
public int Id { get; set; }
public string Name { get; set; }
public Person Person
{
get => Util.ThrowOrGet(_person); ---> "Possible null reference return"
set => _person = value;
}
}
But the the function Util.ThrowOrGet(_person); now says that it's a possible null reference return. If I inline the function, it works as intended.
Is there a way to make a generic function that does this?
If you're only going to use ThrowOrGet on reference types (which you should, as it doesn't make sense for value types), then you should declare it like this:
public static T ThrowOrGet<T>(T? obj) where T : class
{
if (obj == null)
{
throw new InvalidOperationException(
$"Unset property {nameof(obj)}. You probably forgot to Include it");
}
return obj;
}
This says that the function accepts a nullable argument, and always returns a non-nullable reference. It's better to follow this pattern than rely on the attributes, as they're really just there for complex cases, which this is not.

System.MissingMethodException when using propertyGrid

I have a class
class PartitionTemplate
{
public PartitionTemplate()
{
keepLabels = new List<string>();
partitions = new List<partition>();
}
[JsonProperty("keepLabels")]
public List<String> keepLabels { get; set; }
[JsonProperty("slot")]
public int slot { get; set; }
....
}
my goal is to edit it with propertyGrid , using the following code:
PartitionTemplate partiTemplate;
//fi is FileInfo with the class as json using
//Newtonsoft.Json.JsonConvert.DeserializeObject<PartitionTemplate>(File.ReadAllText(partitionfile.FullName));
PartitionTemplate.ReadOrCreatePartitonConfigurationFile(out partiTemplate, fi);
propertyGrid1.SelectedObject = partiTemplate;
my problem is :
when I try to add element to keepLabels i get the following error :
Exception thrown: 'System.MissingMethodException' in mscorlib.dll
Additional information: Constructor on type 'System.String' not found.
how can it be fixed?
This happens because when you click the 'Add' button in the Collection Editor (a standard editor for the property grid) it creates a new item using a supposed public parameterless constructor, which doesn't exist on System.String (you can't do var s = new String();).
What you can do though, if you want to keep the keepLabels property as is, is to create a custom editor, like this:
// decorate the property with this custom attribute
[Editor(typeof(StringListEditor), typeof(UITypeEditor))]
public List<String> keepLabels { get; set; }
....
// this is the code of a custom editor class
// note CollectionEditor needs a reference to System.Design.dll
public class StringListEditor : CollectionEditor
{
public StringListEditor(Type type)
: base(type)
{
}
// you can override the create instance and return whatever you like
protected override object CreateInstance(Type itemType)
{
if (itemType == typeof(string))
return string.Empty; // or anything else
return base.CreateInstance(itemType);
}
}

Buddy class for validation not working

I have the current piece of code :
using System;
using System.ComponentModel.DataAnnotations;
using Boo.Lang;
class Program
{
public partial class Foo
{
public string SomeField { get; set; }
}
[MetadataType(typeof(FooMetadata))]
public partial class Foo
{
}
public class FooMetadata
{
[Required(ErrorMessage = "Some Field is required")]
public string SomeField { get; set; }
}
static void Main()
{
var sample = new Foo { SomeField = null };
var context = new ValidationContext(sample);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(sample, context, results);
if (!isValid)
{
foreach (var validationResult in results)
{
Console.WriteLine(validationResult.ErrorMessage);
}
}
else
Console.WriteLine("sample is valid");
Console.ReadLine();
}
}
It says that sample is valid although it's not the case. Am I missing something ?
Validator.ValidateObject goes through all validation attributes and throws ValidationException for the first one that fails. I don't think one can get the list of all properties that failed this way.
The MSDN documentation is a bit confusing here, it says:
The ValidateObject method evaluates each ValidationAttribute attribute
that is associated with the object type. If validateAllProperties is
set to true, the method validates the property values of the object.
TryValidateObject method manual continues:
It also checks whether each property that is marked with
RequiredAttribute is provided.
I confirm that it always checks all the Required attributes, regardless of validateAllProperties. But if you have, for example, a Range validation attribute it will only check it when validateAllProperties is true (because this is when it validates the property value).
A bit confusing, but as you noticed, TryValidateObject shows all the failed properties.

Omu.ValueInjecter checking property before allowing a set to occur

I need to extend the Omu.ValueInjecter to perform a check before a property assignment is made. Given the code example below, assignment of prop A should only occur if SetA is true. I suspect LoopValueInjection is not the right base class here, but could someone correct the code below so that I can check SetA during the injection process?
var source = new Source() { A = 3 };
var dest = new Dest();
dest.InjectFrom<MyInjector>(source);
public class Source
{
public int A { get; set; }
public bool SetA { get; set; }
}
public class Dest
{
public int A { get; set; }
}
public class MyInjector : LoopValueInjection // or some other base class!
{
protected override bool AllowSetValue(object value)
{
// check SetA!!
//return base.AllowSetValue(value);
}
}
Ok, I have it working now. Below is the correct code. I missed the UseSourceProp overload which served my purposes exactly.
The problem I was trying to solve was with MVC after a view model is posted to an action, you must copy the view model data into the data model. When the data model is initialized there could be certain defaults that are set. And when the view model was injected, those defaults would be overwritten. It would be correct to overwrite those if the view model properties had been set, but I had default values being overwritten by view model values that had not been set from a post operation.
The solution was to put a flag in the view model that would indicate whether a property had been set are not. And the setter for each property I simply updated a common list string object in the base class.
In the code below in the UseSourceProp method, you can see that if the property name being processed does not exist in SetProperties, then the method returns false and the property is not set.
var source = new Source() { A = 3 };
var dest = new Dest();
dest.InjectFrom<MyInjector>(source);
public class Source
{
public int A { get; set; }
public bool SetA { get; set; }
}
public class Dest
{
public int A { get; set; }
}
public class MyInjector : LoopValueInjection // or some other base class!
{
protected override void Inject(object source, object target)
{
if (source is BaseEntityViewModel) _baseEntityViewModel = (BaseEntityViewModel)source;
base.Inject(source, target);
}
protected override bool UseSourceProp(string sourcePropName)
{
if (_baseEntityViewModel is BaseEntityViewModel)
return _baseEntityViewModel.SetProperties.Contains(sourcePropName);
else
return base.UseSourceProp(sourcePropName);
}
}
I think overridding the SetValue method might be what you need. This is a slight modification of the docs from here: http://valueinjecter.codeplex.com/wikipage?title=Getting%20started&referringTitle=Documentation and http://valueinjecter.codeplex.com/discussions/355101
public class MyInjector : LoopValueInjection
{
//by default is return sourcePropertyValue; override to change behaviour
protected override object SetValue(ConventionInfo c)
{
// this is just a sample, but you could write anything here
return new Dest
{
//Check if source value is true and only then set property
if(c.SourceProp.Name == "SetA")
{
var setASourceVal = c.TargetProp.Value As bool;
if(setASourceVal)
{
A = sourcePropertyValue;
}
}
}
}
}
depends which injection your using,
with ConventionInjection you have the value in the Match method
https://valueinjecter.codeplex.com/wikipage?title=step%20by%20step%20explanation&referringTitle=Home
for the LoopValueInjection you can override AllowSetValue
the latest (fastest) injection is this: https://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection&referringTitle=Home
It has one limitation comparing to the ConventionInjection, you don't have the values of the Source and Target Properties in the Match method but you have them in the SetValue Method and you can cancel the setting of the value to that property if you set false to the ref parameter setValue

Storing Reference to Non-Static Method

I'm trying to create a collection of values that each correspond to an action. This way, I'll be able to search the collection for a particular value and then call the associated action in a generic way.
So, here was my first stab at it:
public class CommandInfo
{
public string Name { get; set; }
public Action<RunArgument> Action { get; set; }
}
public class MyClass
{
public List<CommandInfo> Commands = new List<CommandInfo>
{
new CommandInfo { Name = "abc", Action = AbcAction } // <== ERROR HERE
};
public void AbcAction(RunArgument arg)
{
; // Do something useful here
}
}
In this case, the declaration of the new CommandInfo inside the Commands collection gives me the error:
A field initializer cannot reference the non-static field, method, or property 'MyNameSpace.MyClass.AbcAction(MyNameSpace.RunArgument)'
Surely there must be a way to store a reference to a non-static method like this. Can someone help me out?
Surely there must be a way to store a reference to a non-static method like this. Can someone help me out?
There is, just not within a field initializer. So this works fine:
public List<CommandInfo> Commands = new List<CommandInfo>();
public MyClass()
{
Commands.Add(new CommandInfo { Name = "abc",
Action = AbcAction });
}
... or perform the whole assignment within the constructor. Note that this doesn't really have anything to do with delegates - it's incidental, on the basis that you're effectively referring to this.AbcAction. In every other way, it's equivalent to this problem:
public class Foo
{
int x = 10;
int y = this.x; // This has the same problem...
}
(I hope you don't really have a public field, of course...)
The problem isn't that you can't store a reference to a non-static member, it is that you cannot reference a non-static member in a field initializer. Field initializers can only reference static or constant values. Move the initialization of Commands to the constructor and it will work.
public class CommandInfo
{
public string Name { get; set; }
public Action<RunArgument> Action { get; set; }
}
public class MyClass
{
public List<CommandInfo> Commands;
public MyClass
{
Commands = new List<CommandInfo>
{
new CommandInfo { Name = "abc", Action = AbcAction }
};
}
public void AbcAction(RunArgument arg)
{
; // Do something useful here
}
}

Categories