Dictionary inherited from base class cannot be added to from derived class - c#

I have an abstract class for POs.
public abstract class PO
{
public abstract Dictionary<string, object> InvalidFields { get; }
public abstract string PONumber { get; set; }
}
Which is inherited by two different types of PO: CPO and POR.
public class CPO
{
private string poNumber;
public override Dictionary<string, object> InvalidFields => new Dictionary<string, object>();
public override string PONumber
{
get
{
return poNumber;
}
set
{
if (!ValidatePONumber(value)) InvalidFields.Add("CPO Number", value);
poNumber = value;
}
}
}
When ValidatePONumber(value) returns false, it correctly executes InvalidFields.Add() but the dictionary is never actually added to. In the Locals window, a new variable is created named Namespace.PO.InvalidFields.get returned and I can see the new key that is added. However, this.InvalidFields has no values.
So it looks like the dict in the abstract base class PO is being created and added to instead of the derived class CPO.

Thanks to Klaus for pointing out the issue. I resolved by setting up a private invalidFields field and returning that with InvalidFields.get because what I was doing was returning a new Dictionary class with every get.
public class CPO : PO
{
private string poNumber;
private Dictionary<string, object> invalidFields = new Dictionary<string, object>();
public override Dictionary<string, object> InvalidFields { get => invalidFields; }
public override PONumber
{
get
{
return poNumber;
}
set
{
if (!ValidatePONumber(value)) InvalidFields.Add("CPO Number", value);
poNumber = value;
}
}
}

The code as you have given above does not even compile. You derived class is not actually inheriting from the abstract class (I am assuming it is a typo). Even after addition abstract class, the dictionary instantiation throws an error because it is a property definition and missing 'set' definition (InvalidFields is missing 'set' accessor definition.
Also, this sounds to be a duplicate of Overriding fields or properties in subclasses
I have tried this with minor modifications, please see the code below. Like #yransis says in comments, The InvalidFields is being treated as a 'get' property, returning new instance of dictionary every time it is executing the 'Add' step.
class DerivedCpo : AbstractPo
{
private string poNumber;
private Dictionary<string, object> invalidFieldsBackingField;
public override Dictionary<string, object> InvalidFields
{
get
{
return invalidFieldsBackingField;
}
set { this.invalidFieldsBackingField = value; }
}
public DerivedCpo()
{
this.InvalidFields = new Dictionary<string, object>();
}
public override string PoNumber
{
get { return poNumber;}
set
{
if(!ValidatePONumber((value)))
InvalidFields.Add("CPO Number", value);
poNumber = value;
}
}
private bool ValidatePONumber(string value)
{
if (string.IsNullOrEmpty(value))
{
return false;
}
if (value.Length > 5)
return false;
return true;
}
}
Main method calling this class -
static void Main(string[] args)
{
var po = new DerivedCpo();
po.PoNumber = "test1";
po.PoNumber = "thisistheinvalidfieldpo";
if (po.InvalidFields != null && po.InvalidFields.Count > 0)
{
Console.WriteLine(#"There are {0} fields in invalidFields collection", Convert.ToString(po.InvalidFields.Count) );
}
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
In the code above I have added explicit backing field. It is being instantiated only once in the constructor. That way the contents of InvalidFields are persistent. In your code, you are returning a new instance of dictionary, essentially losing the data that was stored between two 'get' calls.

Related

Concise way of deserializing json to an interface?

I have a config service which wraps the baked-in assembly settings, but I'd also like to override these on the command line.
Currently this code is working fine:
public interface ISettings
{
string Url { get; }
}
public class OperationalSettings : ISettings
{
public string Url { get { return ServiceSettings.Default.Url; } }
}
public class CommandLineModel
{
public string Url;
}
public class CommandLineSettings : ISettings
{
private readonly CommandLineModel _model;
public CommandLineSettings(string serialisedSettings)
{
_model = JsonConvert.DeserializeObject<CommandLineModel>(serialisedSettings);
}
public string Url { get { return _model.Url; } }
}
public class ConfigService
{
private readonly ISettings _settings;
public ConfigService(ISettings settings)
{
_settings = settings;
}
public ISettings settings { get { return _settings; } }
}
Then the test driver code:
class Program
{
static void Main(string[] args)
{
ISettings opSettings = new OperationalSettings();
var commandLineTest = "{Url:'http://overridenurl.com'}";
ISettings commandSettings = new CommandLineSettings(commandLineTest);
var configService = new ConfigService(opSettings);
var configServiceUsingCmdOpts = new ConfigService(commandSettings);
}
}
So with this I can override settings using the command line string. However, what I don't like is that if I have a new settings, I now need to add this in 4 places:
The interface
The concrete implementation of the settings wrapper (OperationalSettings)
The command line model for deserialisation
The command line settings implementation that wraps the deserialised model.
This seems to suffer from scalability once I add more properties. Is there a more efficient way to achieve this without so many code changes?
You might take a look at DynamicObject
public class CommandLineModelDictionary : DynamicObject
{
// The inner dictionary.
Dictionary<string, object> dictionary
= new Dictionary<string, object>();
// This property returns the number of elements
// in the inner dictionary.
public int Count
{
get
{
return dictionary.Count;
}
}
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
Otherwise If you have a simple scenario in which you need an object that can only add and remove members at run time but that does not need to define specific operations and does not have static members, use the ExpandoObject class
here how to use
class Program
{
public static dynamic Dyn { get; set; }
static void Main(string[] args)
{
dynamic model= new CommandLineModelDictionary();
model.Prop1 = "Foo";
model.Prop2 = "toto";
Console.WriteLine(model.Prop1);
Console.WriteLine(model.Prop2);
//otherwise you can use
dynamic dynModel = new ExpandoObject();
dynModelop1 = "Test1";
dynModel2 = "Test2";
Console.WriteLine(dynModel.Prop1);
Console.WriteLine(dynModel.Prop2);
}
}

How this way of defining properties is called

public class TestClass
{
private Dictionary<string, int> _testDictionary = new Dictionary<string,int>();
private string _key;
public int this[string key]
{
get { return _testDictionary[key];}
set
{
if (_testDictionary.ContainsKey(key))
_testDictionary[key] = value;
else
_testDictionary.Add(key, value);
}
}
}
public class Program
{
static void Main(string[] args)
{
TestClass test = new TestClass();
test["T1"] = 1;
test["T2"] = 2;
Console.WriteLine(test["T1"]);
Console.WriteLine(test["T2"]);
}
}
So how this way of defining properties is called, I want to read more about that. Also is it possible to have same definition like this in other places, for an example in Methods etc.
Your implementation is right, you could add your desired IndexerName but you don't have to. It is better to add a guide from the getter in case the key is not found, and you return some default value.
Check out this enter link description here
public class TestClass
{
private Dictionary<string, int> _testDictionary = new Dictionary<string, int>();
// you do not need a private property to store the key
// private string _key;
[IndexerName("MyKeyItem")]
public int this[string key]
{
get
{
if (_testDictionary.ContainsKey(key))
{
return _testDictionary[key];
}
return int.MinValue;
}
set
{
if (_testDictionary.ContainsKey(key))
_testDictionary[key] = value;
else
_testDictionary.Add(key, value);
}
}
}
It's called an indexed property.

How to pass generic field to observable collection

I have code as follows
public class Field<T>
{
private T_fieldValue;
public T FieldValue
{
get
{
return _fieldValue;
}
set
{
_fieldValue = value;
}
}
}
public class Container
{
private ObservableCollection<Field> _fieldValues;
public ObservableCollection<Field> FieldValues
{
get { return _fieldValues; }
set { _fieldValues = value; }
}
}
How can I pass my Type parameter in container class as well ??
i.e I am looking for something like
private ObservableCollection<Field<T>> _fieldValues;
EDIT:
I made changes to the class as follows
public class Container<T>
{
public string MyName { get; set; }
private ObservableCollection<Field<T>> _fieldValues;
public ObservableCollection<Field<T>> FieldValues
{
get { return _fieldValues; }
set { _fieldValues = value;}
}
}
}
Now in my Main class how can i call something like
new ObservableCollection<Container>() { MyName ="Kyle",
new Container() { FieldValues = new ObservableCollection<Field<int>>()
{new Field<int>(){FieldValue=10}}; // I am not sure if this syntax is correct
You will need to make the Container class generic as well:
class Container<T> : BindableBase
{
private ObservableCollection<Field<T>> _fieldValues;
}
If you always have a specific T parameter type in mind for Container, then you can of course just hard-code that:
class Container : BindableBase
{
private ObservableCollection<Field<SomeSpecificType>> _fieldValues;
}
To create an instance of your generic Container<T> class, you use the exact same syntax you'd use for any generic type. For example, if T is int, you would use:
new Container<int>()
Then you can assign the FieldValues property as you indicate in your updated example. I.e.:
FieldValues = new ObservableCollection<Field<int>>()

Polymorphism in member fields, when the fields are collections of objects which are also a part of an inheritance tree

I'm having trouble articulating the question so I'll start with an example:
public class BirdCollector
{
protected Dictionary<string, Bird> nameToBird_;
public BirdCollector(Dictionary<string, Bird> nameToBird)
{
nameToBird_ = nameToBird;
}
}
public class ExoticBirdCollector
{
public ExoticBirdCollector(Dictionary<string, Bird> nameToBird)
: base(nameToBird)
{ }
public ExoticBird GetExoticBird(string name)
{
Bird bird;
if(nameToBird_.TryGetValue(name, out bird))
{
return (ExoticBird)bird;
}
else
{
// handle error
return null;
}
}
}
The dictionary I'm passing into the ExoticBirdCollector contains all ExoticBird, which extends Bird, but I am having to re-cast them every time in GetExoticBird().
Is it possible to cast these once, maybe in the constructor, so that everytime I get a bird from nameToBird_ it will be an ExoticBird? The compiler doesn't have any way of knowing that I'm passing all ExoticBirds in the map, so is there a way to enforce this other than declaring a separate dictionary e.g. Dictionary<string, ExoticBird> nameToExoticBird_?
What I'm considering doing now (which seems incorrect) is making nameToBird_ in BirdCollector private instead of protected, and hiding it in ExoticBirdCollector a dictionary of string and ExoticBird.
My original question was answered, but I have a related follow-up. If I were to require the Dictionary<string, ExoticBird> to be passed into a new class which accepts Dictionary<string, Bird> in the constructor, how could I achieve that? I suspect the down-cast can't be made because the objects are inside a container. I could create a new Dictionary<string, Bird> and loop through the Dictionary<string, ExoticBird> to fill it and then pass it, but this seems like a hack.
Make your base class generic and move the GetBird method
public class BirdCollector<T> where T : Bird
{
readonly Dictionary<string, T> nameToBird_;
public BirdCollector(Dictionary<string, T> nameToBird)
{
nameToBird_ = nameToBird;
}
public T GetBird(string name)
{
T bird;
if (nameToBird_.TryGetValue(name, out bird))
{
return bird;
}
// handle error
return null;
}
}
Then you can declare its derived class like this
public class ExoticBirdCollector : BirdCollector<ExoticBird>
{
public ExoticBirdCollector(Dictionary<string, ExoticBird> nameToBird)
: base(nameToBird)
{
}
}
You can use generics and type constraints:
public class Bird
{ }
public class ExoticBird : Bird
{ }
public class BirdCollector<T> where T : Bird
{
protected Dictionary<string, T> nameToBird_;
public BirdCollector(Dictionary<string, T> nameToBird)
{
nameToBird_ = nameToBird;
}
}
public class ExoticBirdCollector : BirdCollector<ExoticBird>
{
public ExoticBirdCollector(Dictionary<string, ExoticBird> nameToBird)
: base(nameToBird)
{ }
public ExoticBird GetExoticBird(string name)
{
ExoticBird bird;
if (nameToBird_.TryGetValue(name, out bird))
{
return bird;
}
else
{
// handle error
return null;
}
}
}

What wrong with Dictionary in property of class?

Why is this code not working?
public class A
{
public Dictionary<int, string> dic { get; set; }
}
class Program
{
public static void Main()
{
A a = new A();
a.dic.Add(1, "a");
}
}
Error:
System.NullReferenceException was unhandled
Message=Object reference not set to an instance of an object.
You haven't initialized the property, so the value of a.dic is null (the default for any reference type).
You'd need something like:
a.dic = new Dictionary<int, string>();
... or you could initialize it in the constructor.
On the other hand, it's rarely a good idea to have such direct access to the inner workings of a class - you basically have no encapsulation here.
Dictionary is a reference type. It's default value is null. There's no "new Dictionary" anywhere in your program; there probably should be.
public class A
{ public Dictionary dic;
A()
{
dic = new Dictionary();
}
}
class Program
{ public static void Main() { A a = new A(); a.dic.Add(1, "a");
}
}
Change the definition of A to something like this:
public class A
{
public Dictionary<int, string> dic { get; set; }
public A()
{
dic = new Dictionary<int, string>();
}
}
The key point is that you need to initialize the "dic" property before you can use it.

Categories