I wanted to create a class and use a method from the initialized class to change the property values of the calling instance. Somehow I have a knot in my brain and there seems to be a basic thinking error of mine. Maybe someone can help me figure it out.
Class Program
{
...
private void Initialize()
{
Zoo myZoo = new Zoo();
myZoo.Load();
Console.WriteLine(myZoo.ZooName);
}
}
and the Zoo-Class:
public class Zoo
{
public string ZooName { get; set; }
...
internal void Load()
{
Zoo myZoo = this;
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
The JSON part works fine, but as soon as the Load()-method comes to an end the myZoo/this is set to NULL. Is there any possibility to use 'this' to modify the property values of the calling class instance?
You probably want to make a factory method on your class instead. This function will return a new instance of Zoo with the data from your json file.
Like this:
public class Zoo
{
public string ZooName { get; set; }
...
public static Zoo Init()
{
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
var myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
return myZoo;
}
}
}
In your Initialize function you can now create an instance like this:
private void Initialize()
{
var myZoo = Zoo.Init();
Console.WriteLine(myZoo.ZooName);
}
other way out.you can use ref keyword for the same.
Class Program
{
...
private void Initialize()
{
Zoo myZoo = new Zoo();
myZoo.Load(ref myZoo);
Console.WriteLine(myZoo.ZooName);
}
}
public class Zoo
{
public string ZooName { get; set; }
...
internal void Load(ref Zoo myZoo)
{
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
You cannot set the this pointer. There also is no assignment operator in C# to overload.
You could copy all properties from your loaded zoo object into the this object.
A more common approach is to have a static factory method to do this for you:
public class Zoo
{
public string ZooName { get; set; }
...
public static Zoo Load(string file)
{
using (StreamReader reader = File.OpenText(file))
{
JsonSerializer serializer = new JsonSerializer();
return (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
Later call it like this:
Zoo z = Zoo.Load(#"C:\Areas.json");
Related
I want to save the information of a model in the Json file I want to implement this in such a way that I can easily store different models So I used this method:
public abstract class SettingBase
{
[JsonIgnore]
public abstract string Filename { get; }
public static T Load<T>() where T : SettingBase, new()
{
T result = new T();
result = JsonFile.Load<T>(result.Filename) ?? result;
return result;
}
public void Save()
{
JsonFile.Save(Filename, this);
}
}
JsonFile:
public static class JsonFile
{
public static void Save<T>(string fileName, T #object)
{
using (StreamWriter writer = File.CreateText(fileName))
{
string json = JsonSerializer.Serialize(#object);
writer.Write(json);
}
}
public static T Load<T>(string fileName)
{
using (StreamReader reader = File.OpenText(fileName))
{
string json = reader.ReadToEnd();
return JsonSerializer.Deserialize<T>(json);
}
return default(T);
}
}
now i can use like this:
var xx = SettingBase.Load<AppModel>();
xx.boo = true;
xx.integ = 25;
xx.str = "sss";
xx.Save();
The problem is that the save operation is not performed and nothing is saved in the json file
How to solve this problem?
Unfortunately, this feature is not currently supported on .NET Core Probably supported in .Net 6.0 You must use newtonsoft.json
public static void Save<T>(string fileName, T #object)
{
var json = JsonSerializer.Serialize(#object);
System.IO.File.WriteAllText(fileName, json);
}
public static T Load<T>(string fileName)
{
var json = System.IO.File.ReadAllText(fileName);
return JsonSerializer.Deserialize<T>(json)
}
I using json .NET to deserialize my json string to my model.
below is what I am trying to achieve, please advice what is best way ..
When there is no data my response looks like below
json string = "{\"message\":\"SUCCESS\",\"result\":null}"
the result eventually is tied to a view. So when the response is null I would like to intialize my view with default model values. And so would like to call Default constructor on deserialization. Default constructor looks like below.
public ProfileModel()
{
this.DefaultTab = DefaultTabOption.PROFILE;
this.DataLoadPosition = new DataLoadPositionOptionsModel();
this.DataLayout = new DataLayoutOptionsModel();
this.NAData = new NADataOptionsModel();
this.DataTable = new DataDisplayOptionsModel();
}
But when there is data, the reponse looks like below.
{"message":"SUCCESS","result":{"dataLayout":{"vertical":false},"dataLoadPosition":{"cell":"B2","cursorLocation":false},"dataTable":{"decimalPts":1},"defaultTab":"BROWSE","naData":{"custom":"","naDataOption":"FORWARDFILL"}}}
In this case, I would like to call my parameterized constructor so that models are initialized correctly.
Deserialization code:
using (StreamReader reader = new StreamReader(responseStream))
{
var t = JsonConvert.DeserializeObject<T>(reader.ReadToEnd());
return t;
}
Where T is my main Model which initilialises multiple models. Below is the parameterized contructor.
public ProfileModel(DefaultTabOption defaultTabModel,
DataLoadPositionOptionsModel dataLoadPositionOption ,
DataLayoutOptionsModel dataLayoutOptios ,
NADataOptionsModel naDataOptions ,
DataDisplayOptionsModel dataTableOptions)
{
this.DefaultTab = defaultTabModel;
this.DataLoadPosition = dataLoadPositionOption;
this.DataLayout = dataLayoutOptios;
this.NAData = naDataOptions;
this.DataTable = dataTableOptions;
}
What is they best way to deserialize so that default constructor is called when null and parameterized is call when not null. I tried the ConstructorHandling, NullValueHandling but I am not able to achieve desired results.
I've a little simplified your model
public sealed class ProfileModel
{
public ProfileModel()
{
DataLayout = new DataLayoutOptionsModel();
}
public ProfileModel(DataLayoutOptionsModel dataLayout)
{
DataLayout = dataLayout;
}
public DataLayoutOptionsModel DataLayout { get; private set; }
}
public sealed class DataLayoutOptionsModel
{
public bool Vertical { get; set; }
}
public class ResultModel
{
public string Message { get; set; }
public ProfileModel Result { get; set; }
}
To choose concrete constructor, you have to implement custom JsonConverter, for example
public sealed class MyJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(ProfileModel).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
ProfileModel target;
JObject jObject = JObject.Load(reader);
JToken resultToken = jObject["Result"];
//This is result null check
if (resultToken.Type == JTokenType.Null)
{
target = new ProfileModel();
}
else
{
var optionsModel = resultToken["DataLayout"].ToObject<DataLayoutOptionsModel>();
target = new ProfileModel(optionsModel);
}
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
So, result serialization looks like:
[Fact]
public void Test()
{
string tinyJsonl = "{\"Message\":\"SUCCESS\",\"Result\":null}";
var defaultProfile = JsonConvert.DeserializeObject<ProfileModel>(tinyJsonl, new MyJsonConverter());
Assert.False(defaultProfile.DataLayout.Vertical);
string fullJson = "{\"Message\":\"SUCCESS\",\"Result\":{\"DataLayout\":{\"Vertical\":true}}}";
var customProfile = JsonConvert.DeserializeObject<ProfileModel>(fullJson, new MyJsonConverter());
Assert.True(customProfile.DataLayout.Vertical);
}
I am trying to serialize IEnumerable using the following code. I am getting the following exception.
There was an error generating the XML document. "A circular reference was detected while serializing an object of type DBML_Project.FixedBankAccount."}.
Why does this error come? How to correct it?
Note: I am already using InheritanceMapping attribute.
public class BankAccountAppService
{
public RepositoryLayer.ILijosBankRepository AccountRepository { get; set; }
public void FreezeAllAccountsForUser(int userId)
{
IEnumerable<DBML_Project.BankAccount> accounts = AccountRepository.GetAllAccountsForUser(userId);
foreach (DBML_Project.BankAccount acc in accounts)
{
acc.Freeze();
}
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
System.Xml.XPath.XPathNavigator nav = xmlDoc.CreateNavigator();
using (System.Xml.XmlWriter writer = nav.AppendChild())
{
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(List<DBML_Project.BankAccount>));
ser.Serialize(writer, accounts);
}
}
}
namespace DBML_Project
{
[System.Xml.Serialization.XmlInclude(typeof(FixedBankAccount))]
[System.Xml.Serialization.XmlInclude(typeof(SavingsBankAccount))]
public partial class BankAccount
{
//Define the domain behaviors
public virtual void Freeze()
{
//Do nothing
}
}
public class FixedBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenFA";
}
}
public class SavingsBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenSB";
}
}
}
Autogenerated Class using LINQ to SQL
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")]
[InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)]
[InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))]
public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged
Use the data contract serializer instead of the xmlserializer:
http://jameskovacs.com/2006/11/18/going-around-in-circles-with-wcf/
I need to make all my entities serializable. So I was thinking in a BaseEntity with a Backup and a Restore method. But in the restore I can't override the object with the saved one because this is read-only.
Any solution or some other way to get the serializable entities?
My code:
internal class BaseEntity
{
private MemoryStream ms = new MemoryStream();
private BinaryFormatter bf = new BinaryFormatter();
public void Backup()
{
bf.Serialize(ms, this);
}
public void Restore()
{
this = (BaseEntity)bf.Deserialize(ms);
}
}
The more common pattern is to not make it the responsibility of your objects to serialize/deserialize themselves; rather, use an external serializer:
var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);
Edit: One way serialization can work is to use the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (or other implementation of IFormatter). To serialize an object you pass the object and a stream. To Deserialize the object, you pass a stream (positioned at the begining of your serialized data), and it returns the serialized object and all its depenedencies.
public static class EntityBackupServices
{
public static MemoryStream Backup (BaseEntity entity)
{
var ms = new MemoryStream();
Serialize (ms, entity);
ms.Position = 0;
return ms;
}
public static void Serialize (Stream stream, BaseEntity entity)
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize (stream, entity);
}
public static BaseEntity Restore (Stream stream)
{
var binaryFormatter = new BinaryFormatter();
var entity = (BaseEntity) binaryFormatter.Deserialize (stream);
return entity;
}
}
One thing a formatter don't do (though the FormatterServices class makes it possible) is modify existing objects. So you probably don't want to have an instance method called Deserialize. You can't really do this: new LionEntity().Deserialize () where it replaces the fields of an existing instance.
Note: You'll need to put Serializable over all your types. Any fields that can't be serialized (because it's either not a struct, or it's not marked as [Serializable] will need to be marked with NonSerialized.
// A test object that needs to be serialized.
[Serializable()]
public class BaseEntity
{
public int member1;
public string member2;
public string member3;
public double member4;
// A field that is not serialized.
[NonSerialized()] public MyRuntimeType memberThatIsNotSerializable;
public TestSimpleObject()
{
member1 = 11;
member2 = "hello";
member3 = "hello";
member4 = 3.14159265;
memberThatIsNotSerializable = new Form ();
}
public MemoryStream Backup ()
{
return EntityBackupServices.Backup (this);
}
}
Edit:
The way I've mentioned is a rather standard and accepted way. If you want to venture into hackdom, you can deserialize the object the way I've mentioned, then use reflection to set each field on your existing object to the value of the deserialized object.
public class BaseEntity
{
void Restore(Stream stream)
{
object deserialized = EntityBackupServices.RestoreDeserialize(stream);//As listed above
if (deserialized.GetType () != this.GetType ())
throw new Exception();
foreach (FieldInfo fi in GetType().GetFields())
{
fi.SetValue(this, fi.GetValue (deserialized));
}
}
}
public IEntidadBase Restore()
{
return (IEntidadBase)bf.Deserialize(ms);
}
#jacklondon how would you do EntitySerializer methods?
You can do serialization process with http://www.servicestack.net/ StackService.Text module for clean entities. You don't need any attribute (serializable/datacontract) in ms way.
public class EntityFoo
{
public string Bar { get; set; }
public EntityFoo (string bar)
{
Bar = bar;
}
}
public class EntityDumper //and the EntitySerializer
{
public static string Dump<T> (T entity)
{
return new TypeSerializer<T> ().SerializeToString (entity);
}
public static T LoadBack<T> (string dump)
{
return new TypeSerializer<T> ().DeserializeFromString (dump);
}
}
public class dump_usage
{
public void start ()
{
string dump = EntityDumper.Dump (new EntityFoo ("Space"));
EntityFoo loaded = EntityDumper.LoadBack<EntityFoo> (dump);
Debug.Assert (loaded.Bar == "Space");
}
}
I don't necessarily recommend this, but here is one pattern for an object that can persist and restore its own state using serialization that creates new instances:
public sealed class MyClass
{
private Data _data = new Data();
//Properties go here (access the public fields on _data)
public void Backup()
{
//Serialize Data
}
public void Restore()
{
//Deserialize Data and set new instance
}
private sealed class Data
{
//Public fields go here (they're private externally [because Data is private], but public to MyClass.)
}
}
Note that this only works if your serializer supports non-public classes. Worst-case, you have to make the nested class public, which is ugly, but doesn't hurt encapsulation (since the instance is private).
there have been quite some posts about this, all trying to serialize a Func delegate.
But could someone think of an alternative, when the use of the delegate is always clear?
We have a generic create command, which takes a delegate as paramater in the constructor. This delegate will create the Item for the create command:
public class CreateCommand<T> : Command
{
public T Item;
protected Func<T> Constructor;
public ClientCreateCommand(Func<T> constructor)
{
Constructor = constructor;
}
public override void Execute()
{
Item = Constructor();
}
}
The command is used like this:
var c = new CreateCommand<MyType>( () => Factory.CreateMyType(param1, param2, ...) );
History.Insert(c);
Then the History serializes the command and sends it to the server. ofc the delegate can't be serialized as is and we get an exception.
Now could someone think of a very simple Constructor class that can be serialized and does the same job than the lambda expresseion? Means it takes a list of paramters and returns an instance of type T, that we then can write somethink like this:
var constructor = new Constructor<MyType>(param1, param2, ...);
var c = new CreateCommand<MyType>(constructor);
History.Insert(c);
How would the Constructor class look like? Thanks for any ideas!
EDIT(2): I've provided a couple of complete example implementations. They are categorized below as "Implementation 1" and "Implementation 2".
Your delegate is essentially a factory. You could define a factory interface and create a class that implements that interface for your Item class. Below is an example:
public interface IFactory<T>
{
T Create();
}
[Serializable]
public class ExampleItemFactory : IFactory<T>
{
public int Param1 { get; set; }
public string Param2 { get; set; }
#region IFactory<T> Members
public Item Create()
{
return new Item(this.Param1, this.Param2);
}
#endregion
}
public class CreateCommand<T> : Command
{
public T Item;
protected IFactory<T> _ItemFactory;
public CreateCommand(IFactory<T> factory)
{
_ItemFactory = factory;
}
public override void Execute()
{
Item = _ItemFactory.Create();
}
}
You would utilize this code in the following manner:
IFactory<Item> itemFactory = new ExampleItemFactory { Param1 = 5, Param2 = "Example!" };
CreateCommand<Item> command = new CreateCommand<Item>(itemFactory);
command.Execute();
EDIT(1): The specific implementations of IFactory<T> that your application needs will be up to you. You could create specific factory classes for each class that you need, or you could create some kind of factory that dynamically creates an instance using, for example, the Activator.CreateInstance function or perhaps using some kind of Inversion of Control framework such as Spring or StructureMap.
Below is a complete example implementation that uses two factory implementations. One implementation can create any type given an array of arguments using that type's constructor with matching parameters. Another implementation creates any type that has been registered with my "Factory" class.
The Debug.Assert statements ensure that everything is behaving as intended. I ran this application without error.
Implementation 1
[Serializable]
public abstract class Command
{
public abstract void Execute();
}
public class Factory
{
static Dictionary<Type, Func<object[], object>> _DelegateCache = new Dictionary<Type, Func<object[], object>>();
public static void Register<T>(Func<object[], object> #delegate)
{
_DelegateCache[typeof(T)] = #delegate;
}
public static T CreateMyType<T>(params object[] args)
{
return (T)_DelegateCache[typeof(T)](args);
}
}
public interface IFactory<T>
{
T Create();
}
[Serializable]
public class CreateCommand<T> : Command
{
public T Item { get; protected set; }
protected IFactory<T> _ItemFactory;
public CreateCommand(IFactory<T> itemFactory)
{
this._ItemFactory = itemFactory;
}
public override void Execute()
{
this.Item = this._ItemFactory.Create();
}
}
// This class is a base class that represents a factory capable of creating an instance using a dynamic set of arguments.
[Serializable]
public abstract class DynamicFactory<T> : IFactory<T>
{
public object[] Args { get; protected set; }
public DynamicFactory(params object[] args)
{
this.Args = args;
}
public DynamicFactory(int numberOfArgs)
{
if (numberOfArgs < 0)
throw new ArgumentOutOfRangeException("numberOfArgs", "The numberOfArgs parameter must be greater than or equal to zero.");
this.Args = new object[numberOfArgs];
}
#region IFactory<T> Members
public abstract T Create();
#endregion
}
// This implementation uses the Activator.CreateInstance function to create an instance
[Serializable]
public class DynamicConstructorFactory<T> : DynamicFactory<T>
{
public DynamicConstructorFactory(params object[] args) : base(args) { }
public DynamicConstructorFactory(int numberOfArgs) : base(numberOfArgs) { }
public override T Create()
{
return (T)Activator.CreateInstance(typeof(T), this.Args);
}
}
// This implementation uses the Factory.CreateMyType function to create an instance
[Serializable]
public class MyTypeFactory<T> : DynamicFactory<T>
{
public MyTypeFactory(params object[] args) : base(args) { }
public MyTypeFactory(int numberOfArgs) : base(numberOfArgs) { }
public override T Create()
{
return Factory.CreateMyType<T>(this.Args);
}
}
[Serializable]
class DefaultConstructorExample
{
public DefaultConstructorExample()
{
}
}
[Serializable]
class NoDefaultConstructorExample
{
public NoDefaultConstructorExample(int a, string b, float c)
{
}
}
[Serializable]
class PrivateConstructorExample
{
private int _A;
private string _B;
private float _C;
private PrivateConstructorExample()
{
}
public static void Register()
{
// register a delegate with the Factory class that will construct an instance of this class using an array of arguments
Factory.Register<PrivateConstructorExample>((args) =>
{
if (args == null || args.Length != 3)
throw new ArgumentException("Expected 3 arguments.", "args");
if (!(args[0] is int))
throw new ArgumentException("First argument must be of type System.Int32.", "args[0]");
if (!(args[1] is string))
throw new ArgumentException("Second argument must be of type System.String.", "args[1]");
if (!(args[2] is float))
throw new ArgumentException("Third argument must be of type System.Single.", "args[2]");
var instance = new PrivateConstructorExample();
instance._A = (int)args[0];
instance._B = (string)args[1];
instance._C = (float)args[2];
return instance;
});
}
}
class Program
{
static void Main(string[] args)
{
var factory1 = new DynamicConstructorFactory<DefaultConstructorExample>(null);
var command1 = new CreateCommand<DefaultConstructorExample>(factory1);
var factory2 = new DynamicConstructorFactory<NoDefaultConstructorExample>(3);
factory2.Args[0] = 5;
factory2.Args[1] = "ABC";
factory2.Args[2] = 7.1f;
var command2 = new CreateCommand<NoDefaultConstructorExample>(factory2);
PrivateConstructorExample.Register(); // register this class so that it can be created by the Factory.CreateMyType function
var factory3 = new MyTypeFactory<PrivateConstructorExample>(3);
factory3.Args[0] = 5;
factory3.Args[1] = "ABC";
factory3.Args[2] = 7.1f;
var command3 = new CreateCommand<PrivateConstructorExample>(factory3);
VerifySerializability<DefaultConstructorExample>(command1);
VerifySerializability<NoDefaultConstructorExample>(command2);
VerifySerializability<PrivateConstructorExample>(command3);
}
static void VerifySerializability<T>(CreateCommand<T> originalCommand)
{
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var stream = new System.IO.MemoryStream())
{
System.Diagnostics.Debug.Assert(originalCommand.Item == null); // assert that originalCommand does not yet have a value for Item
serializer.Serialize(stream, originalCommand); // serialize the originalCommand object
stream.Seek(0, System.IO.SeekOrigin.Begin); // reset the stream position to the beginning for deserialization
// deserialize
var deserializedCommand = serializer.Deserialize(stream) as CreateCommand<T>;
System.Diagnostics.Debug.Assert(deserializedCommand.Item == null); // assert that deserializedCommand still does not have a value for Item
deserializedCommand.Execute();
System.Diagnostics.Debug.Assert(deserializedCommand.Item != null); // assert that deserializedCommand now has a value for Item
}
}
}
EDIT(2): After re-reading the question, I think I got a better idea of what the asker was really trying to get at. Essentially, we still want to take advantage of the flexibility offered by lambda expressions / anonymous delegates, but avoid the serialization issues.
Below is another example implementation that utilizes a Factory<T> class to store delegates used to return instances of type T.
Implementation 2
[Serializable]
public abstract class Command
{
public abstract void Execute();
}
[Serializable]
public abstract class CreateCommand<T> : Command
{
public T Item { get; protected set; }
}
public class Factory<T>
{
private static readonly object _SyncLock = new object();
private static Func<T> _CreateFunc;
private static Dictionary<string, Func<T>> _CreateFuncDictionary;
/// <summary>
/// Registers a default Create Func delegate for type <typeparamref name="T"/>.
/// </summary>
public static void Register(Func<T> createFunc)
{
lock (_SyncLock)
{
_CreateFunc = createFunc;
}
}
public static T Create()
{
lock (_SyncLock)
{
if(_CreateFunc == null)
throw new InvalidOperationException(string.Format("A [{0}] delegate must be registered as the default delegate for type [{1}]..", typeof(Func<T>).FullName, typeof(T).FullName));
return _CreateFunc();
}
}
/// <summary>
/// Registers a Create Func delegate for type <typeparamref name="T"/> using the given key.
/// </summary>
/// <param name="key"></param>
/// <param name="createFunc"></param>
public static void Register(string key, Func<T> createFunc)
{
lock (_SyncLock)
{
if (_CreateFuncDictionary == null)
_CreateFuncDictionary = new Dictionary<string, Func<T>>();
_CreateFuncDictionary[key] = createFunc;
}
}
public static T Create(string key)
{
lock (_SyncLock)
{
Func<T> createFunc;
if (_CreateFuncDictionary != null && _CreateFuncDictionary.TryGetValue(key, out createFunc))
return createFunc();
else
throw new InvalidOperationException(string.Format("A [{0}] delegate must be registered with the given key \"{1}\".", typeof(Func<T>).FullName, key));
}
}
}
[Serializable]
public class CreateCommandWithDefaultDelegate<T> : CreateCommand<T>
{
public override void Execute()
{
this.Item = Factory<T>.Create();
}
}
[Serializable]
public class CreateCommandWithKeyedDelegate<T> : CreateCommand<T>
{
public string CreateKey { get; set; }
public CreateCommandWithKeyedDelegate(string createKey)
{
this.CreateKey = createKey;
}
public override void Execute()
{
this.Item = Factory<T>.Create(this.CreateKey);
}
}
[Serializable]
class DefaultConstructorExample
{
public DefaultConstructorExample()
{
}
}
[Serializable]
class NoDefaultConstructorExample
{
public NoDefaultConstructorExample(int a, string b, float c)
{
}
}
[Serializable]
class PublicPropertiesExample
{
public int A { get; set; }
public string B { get; set; }
public float C { get; set; }
}
class Program
{
static void Main(string[] args)
{
// register delegates for each type
Factory<DefaultConstructorExample>.Register(() => new DefaultConstructorExample());
Factory<NoDefaultConstructorExample>.Register(() => new NoDefaultConstructorExample(5, "ABC", 7.1f));
Factory<PublicPropertiesExample>.Register(() => new PublicPropertiesExample() { A = 5, B = "ABC", C = 7.1f });
// create commands
var command1 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
var command2 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
var command3 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
// verify that each command can be serialized/deserialized and that the creation logic works
VerifySerializability<DefaultConstructorExample>(command1);
VerifySerializability<DefaultConstructorExample>(command2);
VerifySerializability<DefaultConstructorExample>(command3);
// register additional delegates for each type, distinguished by key
Factory<DefaultConstructorExample>.Register("CreateCommand", () => new DefaultConstructorExample());
Factory<NoDefaultConstructorExample>.Register("CreateCommand", () => new NoDefaultConstructorExample(5, "ABC", 7.1f));
Factory<PublicPropertiesExample>.Register("CreateCommand", () => new PublicPropertiesExample() { A = 5, B = "ABC", C = 7.1f });
// create commands, passing in the create key to the constructor
var command4 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
var command5 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
var command6 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
// verify that each command can be serialized/deserialized and that the creation logic works
VerifySerializability<DefaultConstructorExample>(command4);
VerifySerializability<DefaultConstructorExample>(command5);
VerifySerializability<DefaultConstructorExample>(command6);
}
static void VerifySerializability<T>(CreateCommand<T> originalCommand)
{
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var stream = new System.IO.MemoryStream())
{
System.Diagnostics.Debug.Assert(originalCommand.Item == null); // assert that originalCommand does not yet have a value for Item
serializer.Serialize(stream, originalCommand); // serialize the originalCommand object
stream.Seek(0, System.IO.SeekOrigin.Begin); // reset the stream position to the beginning for deserialization
// deserialize
var deserializedCommand = serializer.Deserialize(stream) as CreateCommand<T>;
System.Diagnostics.Debug.Assert(deserializedCommand.Item == null); // assert that deserializedCommand still does not have a value for Item
deserializedCommand.Execute();
System.Diagnostics.Debug.Assert(deserializedCommand.Item != null); // assert that deserializedCommand now has a value for Item
}
}
}