I have two classes as below and I'm using them in two separate Dictionaries. How can I Serialize these two Dictionaries to a single file? my Serialization implementation for a single Dictionary can be found at this link:
Serialize a Dictionary<string, object>
[Serializable]
class Beam
{
public string Name { get; set; }
public double Width { get; set; }
}
[Serializable]
class Column
{
public string Name { get; set; }
public double Width { get; set; }
}
Here are my Dictionaries:
var Dic1 = new Dictionary<string, Beam>
{
{"Beam1", new Beam{Name = "B1", Width = 10}},
{"Beam2", new Beam{Name = "B2", Width = 5}},
};
var Dic2 = new Dictionary<string, Column>
{
{"Column1", new Column{Name = "C1", Width = 10}},
{"Column2", new Column{Name = "C2", Width = 5}},
};
Here is the complete code I've written so far but I'm getting an exception:
[Serializable]
public static class Building
{
public static Dictionary<string, Beam> Beams;
public static Dictionary<string, Column> Columns;
}
[Serializable]
public class Beam
{
public string Name { get; set; }
}
[Serializable]
public class Column
{
public string Name { get; set; }
}
static class Program
{
static void Main()
{
Building.Beams.Add("Beam1", new Beam { Name = "B1"});
Building.Columns.Add("Column1", new Column { Name = "C1" });
Serialize();
}
static void Serialize()
{
var fs = new FileStream("DataFile.dat", FileMode.Create);
var formatter = new BinaryFormatter();
try
{
// I'm getting an excepting here:
// 'Savef.Building' is a 'type' but is used like a 'variable'
formatter.Serialize(fs, Building);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
}
Create a class marked with the Serializable attribute, containing instances of these two dictionaries:
[Serializable]
public class Building
{
public static Building Instance = new Building();
public readonly Dictionary<string, Beam> Beams = new Dictionary<string, Beam>();
public readonly Dictionary<string, Column> Columns = new Dictionary<string, Column>();
public static Dictionary<string, Beam> AllBeams
{
get { return Instance.Beams; }
}
}
EDIT
A Singleton pattern used to avoid the exception.
In the other parts of the code use Building.Instance to access the dictionaries.
EDIT2
A static property introduced: Building.AllBeams. You can use it as shorthand.
Related
[Serializable]
public class DOCharStats
{
public int Stamina { get; set; }
public int maxStamina { get; set; }
}
[Serializable]
public class DOMapStats
{
public int xlocation { get; set; }
public int ylocation { get; set; }
}
//Name of char and stats
public static Dictionary<string, DOCharStats> dCharStats = new Dictionary<string, DOCharStats>();
public static Dictionary<string, DOMapStats> dMapStats = new Dictionary<string, DOMapStats>();
//Name of container and dict.
public static Dictionary<string, object> dContainer = new Dictionary<string, object>();
static void Main(string[] args)
{
DOCharStats newStats = new DOCharStats();
dCharStats.Add("MC", newStats);
Console.WriteLine(dCharStats["MC"].Stamina);
Console.WriteLine(dCharStats["MC"].maxStamina);
newStats.Stamina = 5;
newStats.maxStamina = 10;
Console.WriteLine(dCharStats["MC"].Stamina);
Console.WriteLine(dCharStats["MC"].maxStamina);
DOMapStats mapstats = new DOMapStats();
mapstats.xlocation = 20;
mapstats.ylocation = 40;
dMapStats.Add("MC", mapstats);
//How to access dCharStats(dictionary variant) from a string?
dContainer.Add("_dCharStats",dCharStats);
dContainer.Add("_dMapStats", dMapStats);
}
dCharStats and dMapStats will be modified by other methods while the program is running.
I would like to access & modify dCharStats or dMapStats based on a string. I have tried doing this via dContainer, but I am unable to cast dCharStats(object) to dCharStats(Dictionary<String,DOCharStats>) in a generic fashion.
Is there a way to access an instance dictionary (dCharStats) from a string at runtime?
dContainer.Add(_dCharStats, dCharStats);
dContainer.Add("_dMapStats", dMapStats);
object secondObj = (object)dCharStats;
dynamic someObj = dContainer[_dCharStats];
foreach (dynamic blah in someObj)
{
dynamic internalObj = blah.Value;
int somevalue = internalObj.GetType().GetProperty("Stamina").GetValue(internalObj, null);
internalObj.GetType().GetProperty("Stamina").SetValue(internalObj, 8080, null);
}
Console.WriteLine("After:"+dCharStats["MC"].Stamina);
Console.WriteLine("After:" + dCharStats["MC"].maxStamina);
An hour or two after posting this, it looks like using dynamic variables resolves my issue.
Can someone suggest an alternative way to solve this problem, I don't want to use SWITCH statement in my code.
Class Definition:
public class Rootobject
{
public Must[] must { get; set; }
public Should[] should { get; set; }
}
public class Should
{
public Match match { get; set; }
public Bool _bool { get; set; }
}
public class Must
{
public Match match { get; set; }
public Bool _bool { get; set; }
}
public class Match
{
public string pname { get; set; }
}
public class Bool
{
public string rname { get; set; }
}
Function Definition
public root getobject(string op)
{
Rootobject root = new Rootobject();
op ="must";
switch (op)
{
case "should":
root.should = new Should[1];
Should objShould = new Should();
objShould.match = new Match();
objShould.match.pname = "hello";
root.should[0] = objShould;
break;
case "must":
root.must = new Must[1];
Must objMust = new Must();
objMust.match = new Match();
objMust.match.pname = "hello";
root.must[0] = objMust;
break;
}
return(root);
}
Switch statement is an overhead an new type comes then i may need to add another condition. Can anyone suggest an alternative way of using switch statement.
Based on the comments under your question, I discovered it is possible to implement what #Jon Skeet stated.
You can add an Initialize Method in your RootObject class to create the dictionary (Use a ref Dictionary so to avoid setting the dictionary in your RootObject class that could change the structure of your serialization):
public void Initialize(ref Dictionary<string, Func<Rootobject>> rootDic)
{
Func<Rootobject> shouldFunc = () =>
{
Rootobject root = new Rootobject();
root.should = new Should[1];
Should objShould = new Should();
objShould.match = new Match();
objShould.match.pname = "hello";
root.should[0] = objShould;
return root;
};
Func<Rootobject> mustFunc = () =>
{
Rootobject root = new Rootobject();
root.must = new Must[1];
Must objMust = new Must();
objMust.match = new Match();
objMust.match.pname = "hello";
root.must[0] = objMust;
return root;
};
rootDic.Add("should", shouldFunc);
rootDic.Add("must", mustFunc);
}
And then call it in your getobject method like so:
public static Rootobject getobject(string op)
{
Dictionary<string, Func<Rootobject>> rootDic = new Dictionary<string,Func<Rootobject>>();
Rootobject root = new Rootobject();
root.Initialize(ref rootDic);
if(rootDic.Count > 0)
return rootDic[op].Invoke();
return new Rootobject();
}
You still going to get the same result as the solution in your question even after serializing it.
Is it possible to deserialize part of a binary file?
Basically I have an object similar to below, which I serialize into a binary file.
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> { get; set; } // lots of data in here (order of kB-MB)
}
What I would like is to be able to deserialize only Name and Value by way of populating a ListView for file selection purposes and then deserialize the rest of the file when needed (i.e. the user chooses that file from the ListView).
As always, any help greatly appreciated and if any 3rd party libraries are suggested they would need to be able to be used freely in a commercial environment.
protobuf-net can do that, because it is not tied to the specific type; for example:
using ProtoBuf;
using System.Collections.Generic;
using System.IO;
[ProtoContract]
public class MyOtherObject { }
[ProtoContract]
public class MyObject
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
[ProtoMember(3)]
public IList<MyOtherObject> Items { get; set; }
}
[ProtoContract]
public class MyObjectLite
{
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2)]
public int Value { get; set; }
}
static class Program
{
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
Serializer.Serialize(file, obj);
}
MyObjectLite lite;
using (var file = File.OpenRead("foo.bin"))
{
lite= Serializer.Deserialize<MyObjectLite>(file);
}
}
}
But if you don't want two different types, and/or you don't want to have to add attributes - that can be done too:
using ProtoBuf.Meta;
using System.Collections.Generic;
using System.IO;
public class MyOtherObject { }
public class MyObject
{
public string Name { get; set; }
public int Value { get; set; }
public IList<MyOtherObject> Items { get; set; }
}
static class Program
{
static readonly RuntimeTypeModel fatModel, liteModel;
static Program()
{
// configure models
fatModel = TypeModel.Create();
fatModel.Add(typeof(MyOtherObject), false);
fatModel.Add(typeof(MyObject), false).Add("Name", "Value", "Items");
liteModel = TypeModel.Create();
liteModel.Add(typeof(MyOtherObject), false);
liteModel.Add(typeof(MyObject), false).Add("Name", "Value");
}
static void Main()
{
var obj = new MyObject
{
Name = "abc",
Value = 123,
Items = new List<MyOtherObject>
{
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
new MyOtherObject(),
}
};
using (var file = File.Create("foo.bin"))
{
fatModel.Serialize(file, obj);
}
MyObject lite;
using (var file = File.OpenRead("foo.bin"))
{
lite = (MyObject)liteModel.Deserialize(
file, null, typeof(MyObject));
}
}
}
How about putting the Name and Valueinto a superclass and serializing them separately?
Alternatively, you could maintain a Dictionary and serialize that into one file.
I have a Dictionary variable, the program reads XML files, and then instantiates objects stored in the Dictionary variable by type for performance. I would like to store the Dictionary variable to memcache for reuse, but, because the Dictionary variable and instantiated objects are reference types, when I operate instantiated objects to change some value, the cache value of memcache also changed.
Code like the following.
Dictionary variable and XPathNavigator variable of class can't serialize. How can I Serialize/DeSerialize or achieve a similar effect? Thanks.
namespace ObjectReference
{
public interface IMyObject
{
int Id { get; set; }
string Url { get; set; }
bool State { get; set; }
bool SetItemXml(XPathNavigator navigator);
}
[Serializable]
public class MyLink : IMyObject
{
public int Id { get; set; }
public string Url { get; set; }
public bool State { get; set; }
private XPathNavigator _xmlNavigator;
public bool SetItemXml(XPathNavigator navigator)
{
_xmlNavigator = navigator.Clone();
Id = int.Parse(_xmlNavigator.SelectSingleNode("id").Value);
Url = _xmlNavigator.SelectSingleNode("url").Value;
return true;
}
}
[Serializable]
public class MyPicture : IMyObject
{
public int Id { get; set; }
public string Url { get; set; }
public bool State { get; set; }
private XPathNavigator _xmlNavigator;
public bool SetItemXml(XPathNavigator navigator)
{
_xmlNavigator = navigator.Clone();
Id = int.Parse(_xmlNavigator.SelectSingleNode("id").Value);
Url = _xmlNavigator.SelectSingleNode("url").Value;
return true;
}
}
public partial class _Default : System.Web.UI.Page
{
public IDictionary<string, IDictionary<int, IMyObject>> CreateObjects()
{
IDictionary<string, IDictionary<int, IMyObject>> objects = new Dictionary<string, IDictionary<int, IMyObject>>();
var reader = new XmlTextReader(new StringReader(#"<?xml version='1.0' encoding='utf-8'?><root><item><type>MyLink</type><id>1</id><url>http://www.google.com</url></item><item><type>MyLink</type><id>2</id><url>http://stackoverflow.com</url></item><item><type>MyPicture</type><id>3</id><url>http://static.adzerk.net/Advertisers/2565.png</url></item></root>"));
XPathNavigator navigator = new XPathDocument(reader).CreateNavigator();
XPathNodeIterator nodes = navigator.Select("//root/item");
while (nodes.MoveNext())
{
string classType = nodes.Current.SelectSingleNode("type").Value;
int id = int.Parse(nodes.Current.SelectSingleNode("id").Value);
if (!objects.ContainsKey(classType) || !objects[classType].ContainsKey(id))
{
IMyObject myObject = Activator.CreateInstance(Type.GetType(string.Concat("ObjectReference.", classType))) as IMyObject;
myObject.SetItemXml(nodes.Current);
if (!objects.ContainsKey(classType))
objects.Add(classType, new Dictionary<int, IMyObject>() { { id, myObject } });
else if (!objects[classType].ContainsKey(id))
objects[classType].Add(id, myObject);
}
}
return objects;
}
protected void Page_Load(object sender, EventArgs e)
{
IDictionary<string, IDictionary<int, IMyObject>> ObjectList = new Dictionary<string, IDictionary<int, IMyObject>>();
if (HttpContext.Current.Cache["ObjectCache"] != null)
{
ObjectList = (Dictionary<string, IDictionary<int, IMyObject>>)HttpContext.Current.Cache["ObjectCache"];
}
else
{
ObjectList = CreateObjects();
HttpContext.Current.Cache.Insert(
"ObjectCache",
ObjectList,
null,
DateTime.Now.AddMinutes(2),
System.Web.Caching.Cache.NoSlidingExpiration);
}
foreach(var parent in ObjectList)
{
foreach(var child in ObjectList[parent.Key])
{
if(false == child.Value.State)
{
//TODO... Note here
child.Value.State = true;
}
}
}
}
}
}
Have a look at something like XML Serializable Generic Dictionary
I have a number of "section items" (Lesson, Info) which inherit from the common type SectionItem. The various types of SectionItems share some but not all properties.
I have found the best way to pass parameters to each kind of object is to pack them all in a Dictionary<string, object> and then let the base class SectionItem unpack the common ones, and each inheriting class unpack the specific ones.
This works well enough, but this is all very C#2 since I will only catch errors at runtime and not during compilation. Is there a way to do this more elegantly perhaps with generics?
(source: deviantsart.com)
using System;
using System.Collections.Generic;
using System.Text;
namespace TestPass234
{
class Program
{
static void Main(string[] args)
{
List<SectionItem> sectionItems = new List<SectionItem>();
{
Dictionary<string, object> vars = new Dictionary<string, object>();
vars.Add("sectionNumber", 1);
vars.Add("title", "Lesson #1");
vars.Add("startDate", new DateTime(2008, 12, 25));
List<Flashcard> flascards = new List<Flashcard>();
flascards.Add(new Flashcard { Question = "What color is the sky?", Answer = "blue" });
flascards.Add(new Flashcard { Question = "What color is the sun?", Answer = "yellow" });
vars.Add("flashcards", flascards);
SectionItem sectionItem = SectionItem.Instantiate("lesson", vars);
sectionItems.Add(sectionItem);
}
{
Dictionary<string, object> vars = new Dictionary<string, object>();
vars.Add("title", "Info #1");
vars.Add("content", "This is info number one.");
SectionItem sectionItem = SectionItem.Instantiate("info", vars);
sectionItems.Add(sectionItem);
}
foreach (var sectionItem in sectionItems)
{
Console.WriteLine(sectionItem.Render());
}
Console.ReadLine();
}
}
public class SectionItem
{
protected string _title;
public SectionItem()
{ }
public SectionItem(Dictionary<string, object> vars)
{
_title = Convert.ToString(vars["title"]);
}
public static SectionItem Instantiate(string idCode, Dictionary<string, object> vars)
{
switch (idCode)
{
case "lesson":
return new SectionItemLesson(vars);
case "info":
return new SectionItemInfo(vars);
default:
return new SectionItem();
}
}
public virtual string Render()
{
return "undefined section item";
}
}
public class SectionItemLesson : SectionItem
{
private int _sectionNumber;
private DateTime _startDate;
private List<Flashcard> _flashcards = new List<Flashcard>();
public SectionItemLesson(Dictionary<string, object> vars) : base(vars)
{
_sectionNumber = Convert.ToInt32(vars["sectionNumber"]);
_startDate = Convert.ToDateTime(vars["startDate"]);
_flashcards = vars["flashcards"] as List<Flashcard>;
}
public override string Render()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(String.Format(">>> {0}. {1} (Starts {2:ddd, MMM d, yyyy})", _sectionNumber, _title, _startDate));
foreach (var flashcard in _flashcards)
sb.AppendLine(" - " + flashcard.Render());
return sb.ToString();
}
}
public class SectionItemInfo : SectionItem
{
private string _content;
public SectionItemInfo(Dictionary<string, object> vars)
: base(vars)
{
_content = Convert.ToString(vars["content"]);
}
public override string Render()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(String.Format(">>> {0}", _title));
sb.AppendLine(String.Format(" {0}", _content));
return sb.ToString();
}
}
public class Flashcard
{
public string Question { get; set; }
public string Answer { get; set; }
public string Render()
{
return "Q: " + Question + " A: " + Answer;
}
}
}
Can you just create a 'parameters' class for each SectionItem class?
public class SectionItemParameters
{
public string Title { get; set; }
}
public class SectionItemLessonParameters
: SectionItemParameters
{
public int SectionNumber { get; set; }
public DateTime StartDate { get; set; }
public List<Flashcard> Flashcards { get; set; }
}
public class SectionItemInfoParameters
: SectionItemParameters
{
public string Content { get; set; }
}
Then, every class in the hierarchy can receive its parameters in a strongly typed object. Your factory method Instantiate would take in a SectionItemParameters and cast to the appropriate type for the constructor being called.
If the set of possible names is known at compile time and using C#4 you could use default/optional parameters on the constructor. If only certain combinations are valid (e.g. only supply "Foo" if neither "Bar" and "Baz" are supplied) then you will still need runtime checks.
But if the set of names is truly dynamic, then there are only the options of a dictionary or anonymous type (and use reflection to extract the set of names in the body).