How to implement property with parameter - c#

I'm trying to implement a class with a property which can be accessed only with parameter. To clear my question see how I intend to use it
Note that this is different than Indexer. Please don't flag for duplicate.
My incomplete class
public class Inventory{
public object Options..... // I don't know how to define this property
}
How I'm going to use it
Inventory inv = new Inventory();
string invLabel = (string)inv.Options["Label"];
int size = inv.Options["Size"];
inv.Options["Weight"] = 24;
Internally, Options reads data from a private Dictionary. Please help me on how I can define the Options property.
Note: This is different than Indexer. With Indexer, I can use below code:
int size = inv["Size"];
But my usage is different.

I found a way to implement it.
public class Options
{
public Dictionary<string, object> _options;
public Options()
{
_options = new Dictionary<string, object>();
}
public object this[string key] {
get { return _options.Single(r => r.Key == key).Value; }
set { _options[key] = value; }
}
}
public class Inventory
{
public Inventory()
{
Options = new Options();
}
public Options Options { get; set; }
}
Usage:
var x = new Inventory();
x.Options["Size"] = 120;
x.Options["Box"] = "4 x 4 x 8";
Console.WriteLine(x.Options["Size"]);
Console.WriteLine(x.Options["Box"]);

Related

How to address specific element in list

I want to create "list of list of list". It should be:
Group (has a list of Members)
Member (has a Name and list of Properties)
Property (has Name and Value)
What I want is to have a possibility to add Property into Member (specified by its name) inside defined Group. Someting like this:
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
I have trouble achieving this using list... I found class Hashable, but I am not sure if this is usable... and cannot make it works too...
Thank for any suggestion :)
Well, I suggest you create a custom class instead of your approach. But otherwise you can use a Dictionary.
var properties = new Dictionary<string, string>();
properties.Add("Prop1", "Value");
var members = new Dictionary<string, Dictionary<string, string>>();
members.Add("Member1", properties);
var group = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
group.Add("GroupName", members);
public class Group
{
public Group()
{
Members = new List<Member>();
}
public IEnumerable<Member> Members { get; set; }
}
public class Member
{
public Member()
{
Properties = new Dictionary<string, string>();
}
public string Name { get; set; }
IDictionary<string, string> Properties { get; set; }
}
The dictionary can take a key and a value, and the key should be unique.
You can also create a class property if you want to add another thing beside the name and the value
I would use indexers.
Here's a partial implementation:
class Group
{
private List<Member> _members;
public string this
{
get
{
return _members.Find(m => m.Name == value);
}
// You can also implement set here if you want...
}
}
class Member
{
private List<Property> _properties;
public string Name {get;set;}
public string this
{
get
{
return _properties.Find(m => m.Name == value);
}
}
}
class Property
{
public string Name {get;set;}
public string Value {get;set;}
}
And the usage:
var g = new Group();
g[memberName][propertyName].Value = someValue;
Note: This implementation is partial! it still needs constructor logic and any other logic you might need.
Likely the best solution is to use the C# class Dictionary - as suggested by zetawars, or a custom class - as suggested by Zohar Peled, or some mix of the two - as suggested by gandalf.
However, in order to use syntax similar to what is requested in the question...
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
You can abuse ExpandoObject and Action, and do something awesome like this:
dynamic membersgroup = new ExpandoObject();
var getNewMemberObject = new Func<dynamic>(() =>
{
dynamic memberObject = new ExpandoObject();
var addPropertyAction = new Action<string, string>((propertyName, propertyValue) =>
{
((IDictionary<string, object>)memberObject).Add(propertyName, propertyValue);
});
memberObject.AddProperty = addPropertyAction;
return memberObject;
});
var addNewMemberAction = new Action<string>((memberName) =>
{
((IDictionary<string, object>)membersgroup).Add(memberName, getNewMemberObject());
});
membersgroup.AddNewMember = addNewMemberAction;
string memberXYZ = nameof(memberXYZ);
string nameXYZ = nameof(nameXYZ);
string valueXYZ = nameof(valueXYZ);
// look we did it!
membersgroup.AddNewMember(memberXYZ);
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ);
// and it actually works
var actualValue = membersgroup.memberXYZ.nameXYZ;
Console.WriteLine(actualValue); // "valueXYZ"
(for science of course)

Unable to create a "set" accessor for Dictionary

I was originally experiencing a problem in my code in which I was unable to "add" an item to a list object. After reviewing the list object however, I realized it only contained a "get", not a "set". So, I'm trying to create a set accessor but I'm having issues:
Here's my original code to add an item to the list object. Currently, nothing gets added:
ClientCompany clientCompany = new ClientCompany();
LocationData urlData = new LocationData();
Location location = urlData.LocationGet(1129); //hardcoded 1129 in for now
clientCompany.Locations.Add(location); //"location" is NOT null, however nothing gets added to Locations object
return clientCompany; //clientCompany.Locations.Count = 0 (it should equal 1)
And here's the current portion of the ClientCompany class I'm having trouble with:
public Dictionary<int, Location> LocationsDict { get; set; }
// List Properties
public List<Location> Locations
{
get { return LocationsDict.Values.ToList(); }
}
I tried including a setter, but I receive the following error:
Cannot convert source type
Systems.Collections.Generic.List<MyCompany.MVC.MyProject.Models.ClientCompany.Location>'
to target type 'Systems.Collections.Generic.Dictionary<int,
MyCompany.MVC.MyProject.Models.ClientCompany.Location>
get { return LocationsDict.Values.ToList(); }
set { LocationsDict = value; }
Any idea what I'm doing wrong?
Thanks
i 'll do something like this:
private Dictionary<int, Location> LocationsDict = new Dictionary<int, Location>();
public void Set(int key, Location value)
{
if (LocationsDict.ContainsKey(key))
LocationsDict[key] = value;
else
LocationsDict.Add(key, value);
}
public Location Get(int key)
{
return LocationsDict.ContainsKey(key) ? LocationsDict[key] : null; }
}
or better (i think) you could use indexer:
public class MyClass
{
private readonly IDictionary<int, Location> LocationsDict = new Dictionary<int, Location>();
public Location this[int key]
{
get { return LocationsDict.ContainsKey(key) ? LocationsDict[key] : null; }
set
{
if (LocationsDict.ContainsKey(key))
LocationsDict[key] = value;
else
LocationsDict.Add(key, value);
}
}
}
var gotest = new MyClass();
gotest[0] = new Location(){....};

Editing an enum in a class (member cannot be accessed with an instance reference)

I'm trying to edit an enum value in a class instance based on whether that instance appears in a dictionary of type <string, myClass>. What seems logical to me is to do the code snippets below:
if (pumpDict.ContainsKey(ID))
{
foreach(KeyValuePair<string, PumpItem> kvp in pumpDict)
{
if(kvp.Key == ID)
{
kvp.Value.state = kvp.Value.state.Available; //error here
kvp.Value.fuelPumped = fuelPumped;
kvp.Value.fuelCost = fuelCost;
break;
}
}
}
else
{
PumpItem pump = new PumpItem();
pumpDict.Add(ID, pump);
}
And my PumpItems class is such:
namespace PoSClientWPF
{
public enum pumpState
{
Available,
customerWaiting,
Pumping,
customerPaying
};
public enum fuelSelection
{
Petrol,
Diesel,
LPG,
Hydrogen,
None
};
class PumpItem
{
public double fuelPumped;
public double fuelCost;
public fuelSelection selection;
public pumpState state;
public PumpItem()//intialize constructor
{
this.fuelPumped = 0;
this.fuelCost = 0;
this.selection = fuelSelection.None;
this.state = pumpState.Available;
}
}
}
I was led to believe that to have an enum value in a constructor, they have to be set up as above, with a new instance of those enums declared in the class body.
It seems to me, that what I'm trying to do is logical but I am getting an error on the right hand side of the assignation which states:
"member PoSClientWPF.pumpState.Available cannot be accessed with an instance reference; qualify is with a type name instead"
I've searched for this error among several forums but only seem to find errors involving calling static variables incorrectly. Can anyone point me in the direction of a solution?
Thanks in advance.
You are incorrectly accessing the Enum member:
// this is incorrect
kvp.Value.state = kvp.Value.state.Available; //error here
// this is the correct way
kvp.Value.state = PoSClientWPF.pumpState.Available;
You know you have a dictionary?
PumpItem pumpItem = pumpDict[ID];
pumpItem.state = PoSClientWPF.pumpState.Available;
or
PumpItem pumpItem;
if (pumpDict.TryGetValue(ID, out pumpItem))
{
pumpItem.state = PoSClientWPF.pumpState.Available;
}
else
{
pumpItem = new PumpItem();
pumpDict.Add(ID, pumpItem);
}
Could just add ID to PumpItem and use a List
PumpItem pumpItem = pumpList.FirstOrDefualt(x => x.ID == ID)
if (pumpItem == null)
pumpList.Add(new PumpItem(ID));
else
pumpItem.state = PoSClientWPF.pumpState.Available;
class PumpItem
{
public double fuelPumped = 0;
public double fuelCost = 0;
public fuelSelection selection = fuelSelection.None;
public pumpState state = pumpState.Available;
public Int32? ID = null;
public PumpItem()//intialize constructor
{ }
public PumpItem(Int32? ID)
{
this.ID = ID;
}
}

multi return type in c# methods

I have a (string, object) dictionary, object (class) has some values including data type which is defined by enum. I need a GetItemValue method that should return dictionary item's value. So return type must be the type which is defined in item object.
Class Item
{
String Name;
DataValueType DataType;
Object DataValue;
}
private Dictionary<string, Item> ItemList = new Dictionary<string, Item>();
void Main()
{
int value;
ItemList.Add("IntItem", new Item("IntItem", DataValueType.TInt, 123));
value = GetItemValue("IntItem"); // value = 123
}
What kind of solution can overcome this problem?
Best Regards,
You can use Generic Classes
Class Item<T>
{
String Name;
T DataTypeObject;
Object DataValue;
public T GetItemValue()
{
//Your code
return DataTypeObject;
}
}
A better solution would be to introduce an interface that you make all the classes implement. Note that the interface doesn't necessarily have to specify any behavior:
public interface ICanBePutInTheSpecialDictionary {
}
public class ItemTypeA : ICanBePutInTheSpecialDictionary {
// code for the first type
}
public class ItemTypeB : ICanBePutInTheSpecialDictionary {
// code for the second type
}
// etc for all the types you want to put in the dictionary
To put stuff in the dictionary:
var dict = new Dictionary<string, ICanBePutInTheSpecialDictionary>();
dict.add("typeA", new ItemTypeA());
dict.add("typeB", new ItemTypeB());
When you need to cast the objects to their specific types, you can either use an if-elseif-block, something like
var obj = dict["typeA"];
if (obj is ItemTypeA) {
var a = obj as ItemTypeA;
// Do stuff with an ItemTypeA.
// You probably want to call a separate method for this.
} elseif (obj is ItemTypeB) {
// do stuff with an ItemTypeB
}
or use reflection. Depending on how many choices you have, either might be preferrable.
If you have a 'mixed bag' you could do something like this...
class Item<T>
{
public String Name { get; set; }
public DataValueType DataType { get; set; }
public T DataValue { get; set; }
}
class ItemRepository
{
private Dictionary<string, object> ItemList = new Dictionary<string, object>();
public void Add<T>(Item<T> item) { ItemList[item.Name] = item; }
public T GetItemValue<T>(string key)
{
var item = ItemList[key] as Item<T>;
return item != null ? item.DataValue : default(T);
}
}
and use it like...
var repository = new ItemRepository();
int value;
repository.Add(new Item<int> { Name = "IntItem", DataType = DataValueType.TInt, DataValue = 123 });
value = repository.GetItemValue<int>("IntItem");
If you have just a couple types - you're better off with Repository<T>.
I found a solution exactly what I want. Thanks to uncle Google.
Thanks all of you for your kind interest.
public dynamic GetValue(string name)
{
if (OpcDataList[name].IsChanged)
{
OpcReflectItem tmpItem = OpcDataList[name];
tmpItem.IsChanged = false;
OpcDataList[name] = tmpItem;
}
return Convert.ChangeType(OpcDataList[name].ItemValue.Value, OpcDataList[name].DataType);
}

Reflection - object comparison & default values

I'm trying to compare two complex objects in C#, and produce a Dictionary containing the differences between the two.
If I have a class like so:
public class Product
{
public int Id {get; set;}
public bool IsWhatever {get; set;}
public string Something {get; set;}
public int SomeOtherId {get; set;}
}
And one instance, thus:
var p = new Product
{
Id = 1,
IsWhatever = false,
Something = "Pony",
SomeOtherId = 5
};
and another:
var newP = new Product
{
Id = 1,
IsWhatever = true
};
To get the differences between these, i'm doing stuff that includes this:
var oldProps = p.GetType().GetProperties();
var newProps = newP.GetType().GetProperties();
// snip
foreach(var newInfo in newProps)
{
var oldVal = oldInfo.GetValue(oldVersion, null);
var newVal = newInfo.GetValue(newVersion,null);
}
// snip - some ifs & thens & other stuff
and it's this line that's of interest
var newVal = newInfo.GetValue(newVersion,null);
Using the example objects above, this line would give me a default value of 0 for SomeOtherId (same story for bools & DateTimes & whathaveyou).
What i'm looking for is a way to have newProps include only the properties that are explicitly specified in the object, so in the above example, Id and IsWhatever. I've played about with BindingFlags to no avail.
Is this possible? Is there a cleaner/better way to do it, or a tool that's out there to save me the trouble?
Thanks.
There is no flag to tell if you a property was explicitly set. What you could do is declare your properties as nullable types and compare value to null.
If i understand you correctly, this is what microsoft did with the xml wrapping classes, generated with the xsd utility, where you had a XIsSpecified, or something like that, for each property X.
So this is what You can do as well - instead of public int ID{get;set;}, add a private member _id , or whatever you choose to call it, and a boolean property IDSpecified which will be set to true whenever Id's setter is called
I ended up fixing the issue without using reflection (or, not using it in this way at least).
It goes, more or less, like this:
public class Comparable
{
private IDictionary<string, object> _cache;
public Comparable()
{
_cache = new Dictionary<string, object>();
}
public IDictionary<string, object> Cache { get { return _cache; } }
protected void Add(string name, object val)
{
_cache.Add(name, val);
}
}
And the product implementation goes to this:
public class Product : Comparable
{
private int _id;
private bool _isWhatever;
private string _something;
private int _someOtherId;
public int Id {get { return _id; } set{ _id = value; Add("Id", value); } }
public bool IsWhatever { get { return _isWhatever; } set{ _isWhatever = value; Add("IsWhatever ", value); } }
public string Something {get { return _something; } set{ _something = value; Add("Something ", value); } }
public int SomeOtherId {get { return _someOtherId; } set{ _someOtherId = value; Add("SomeOtherId", value); } }
}
And the comparison is then pretty straightforward
var dic = new Dictionary<string, object>();
foreach(var obj in version1.Cache)
{
foreach(var newObj in version2.Cache)
{
//snip -- do stuff to check equality
dic.Add(....);
}
}
Doesn't hugely dirty the model, and works nicely.

Categories