C# Is there a way to exclude a member from serialization dynamically? - c#

C# Is there a way to exclude a member from serialization dynamically?
e.g. (I make up this code, not real)
class def:
[Serializable]
public class Class1
{
public int Property1{get;set;}
}
and I do
Class1 c=new Class(){Property1=15};
SerializationOption option = new SerializationOption(){ExludeList=new List(){"Property1"}};
var result=Serialize(Class1,option);

The only way to control this is to implement ISerializable on the class and have access to some context during serialization. For example:
public class Class1 : ISerializable
{
// ....
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
var excludeList = (List<String>)context.Context;
if(!excludeList.Contains("Property1"))
{
info.AddValue("Property1",Property1);
}
}
}
You provide this context during creating of the formatter. For example:
var sc = new StreamingContext(StreamingContextStates.All,
new List<String> { "Property1" });
var formatter = new BinaryFormatter(null, sc);

Related

How to apply generic constraint to accept multi level of inheritance C#

I am looking for a way to support multi level of inheritance for generic type constraint.
Common generic interface
public interface ICommon<T>
{
T OrignalData {get;set;}
string ChangeJson {get;set;}
T Merged {get;set;}
void Inject();
}
Common base class implements ICommon
public class Base <T>: ICommon<T>
{
public T OrignalData {get;private set;}
public string ChangeJson {get;set;}
public T Merged {get;private set;}
public void Inject(T orignal)
{
if (orignal == null)
return;
var settings = new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Auto
};
dynamic merged = orignal.Clone();
JsonConvert.PopulateObject(this.ChangeJson, merged, settings);
this.Merged = merged;
this.Orignal = orignal;
}
}
Department class inherits Base class
public class Deparment : Base<Deparment>
{
}
OrgnizationDepartment class inherits Deparment
public class OrgnizationDepartment : Deparment
{
}
class View expect ICommon must implement on passed calls
public class View<T> where T : ICommon<T>
{
//This class is totally dynamic to visualize any json data along with old and new value of requested json for any class like department or org..
}
Test
public class Test
{
public void TestConstraint()
{
//No error
var deptView = new View<Deparment>();
//Error as Base not directly implemented on OrgnizationDepartment
var orgView = new View<OrgnizationDepartment>();
}
}
how do I define my constraint that should support for multi level as well.
One way out of this would be "composition over inheritance".
Here is a naive example, that is still relatively close to your code:
using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
//No error
var deptView = new View<Deparment>();
//Formerly Error
var orgView = new View<OrgnizationDepartment>();
}
}
public interface ICommon<T> where T : ICloneable
{
// returns a tuple
(T,T,string) Inject(T original, string change);
}
public class Base <T>: ICommon<T> where T : ICloneable
{
// we can reuse this...
private readonly JsonSerializerSettings settings = new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Auto
};
public (T,T,string) Inject(T original, string change)
{
if (original is null)
return default;
// this forces T to implement ICloneable ... just saying...
dynamic merged = original.Clone();
JsonConvert.PopulateObject(change, merged, settings);
return (original, merged, change);
}
}
public class Deparment : ICloneable, ICommon<Deparment>
{
// could also be created in ctor. Maybe use Ctor injection.
private readonly Base<Deparment> common = new Base<Deparment>();
public object Clone(){return this;} // this is of course nonsense. Clone properly! I did this to avoid dotnetfiddle screaming at me.
public (Deparment, Deparment, string) Inject(Deparment original, string change){
return common.Inject(original, change);
}
}
public class OrgnizationDepartment : ICloneable, ICommon<OrgnizationDepartment>
{
private readonly Base<OrgnizationDepartment> common = new Base<OrgnizationDepartment>();
public object Clone() {return this;}
public (OrgnizationDepartment, OrgnizationDepartment, string) Inject(OrgnizationDepartment original, string change){
return common.Inject(original, change);
}
}

Variance for interface tree structure

I am struggling to cast in a tree hierarchy structure below is an example of the class hierarchy structure I would really appreciate if someone can point me in the right direction.
I am unable to cast
var myobj2 = (IR<JB>)JR;
Classes:
public class BASEA{ }
public class B: BASEA{ }
public class C: B{ }
public interface IR<T> { }
public abstract class JR<T> : IR<T> where T : B
{ public abstract void SetRule(); }
public class Action: JB<C>
{
public override void SetRule()
{
//Logic
}
}
public static class RuleLib
{
public static void ApplyTest<T>(T obj, IR<T> JB) where T:B
{
var myobj2 = (IR<JB>)JR; //=> does not cast!
}
}
public class Test
{
[Test]
public void demo()
{
var obj = new B();
var action = new Action();
RuleLib.ApplyRule(obj,action);
}
}
For this to work, your IRule interface needs to be covariant. The example given here shows the following covariance:
IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
This is basically exactly what you're doing. So in your code all you need to do is write
public interface IRule<out T> { ... }
instead of
public interface IRule<T> { ... }
This makes it so that you can cast from an IRule<U> to IRule<V> where U is a subclass of V (e.g. casting from IRule<ShiftAction> to IRule<Job>).

Serializing IEnumerable Containing Derived classes: Circular Reference Issue

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/

c# programming code optimization

I have about 20 classes which are derived from ConvertApi classes. Every class share Convert method from parent class and has unique property SupportedFiles. I use these classes for file manipulation and my code looks like
if (fileEx=="txt")
new Text2Pdf().Convert(file)
else
if (fileEx=="doc")
new Word2Pdf().Convert(file)
else
//and so on..
I know that these code can be optimized because 20 times if operator is repeated and that looks bad, but can't find a way to do that. Could anyone help me?
class Text2Pdf : ConvertApi
{
enum SupportedFiles { txt, log };
}
class Word2Pdf : ConvertApi
{
enum SupportedFiles { doc, docx };
}
class Excel2Pdf : ConvertApi
{
enum SupportedFiles { xls, xlsx };
}
class ConvertApi
{
public void Convert(....);
}
In your base class, have something like this:
public abstract class ConvertApi
{
protected abstract string[] SupportedFilesImpl();
public bool Supports(string ext)
{
return SupportedFilesImpl.Contains(ext);
}
}
Now, your derived classes can implement this method:
public class Text2PDF : ConvertApi
{
protected override string[] SupportedFilesImpl { return new string[] { "txt", "log"}; }
}
public class Doc2PDF : ConvertApi
{
protected override string[] SupportedFilesImpl { return new string[] { "doc", "docx"}; }
}
... and so on for the rest of the converters. Then put these in a list...
List<ConvertApi> converters = new List<ConvertApi>();
converters.Add(new Text2PDF());
converters.Add(new Doc2PDF());
(Note, I'd probably have a class containing these rather than just a list, but anyway). Now, to find a converter:
foreach(ConvertApi api in converters)
{
if(api.Supports(fileExt))
{
// woo!
break;
}
}
Assuming each converter is stateless, it sounds like you just want a Dictionary<string, ConvertApi>:
private static readonly Dictionary<string, ConvertApi> ConverterByType =
new Dictionary<string, ConvertApi>
{
{ "txt", new Text2PdfConverter() },
{ "doc", new Word2PdfConverter() },
...
};
...
ConvertApi converter;
if (!ConverterByType.TryGetValue(fileEx, out converter))
{
// No converter available... do whatever
}
else
{
converter.Convert(file);
}
(The dictionary initialization will end up creating more converters than you really need for any converter that supports multiple extensions, but that's a different matter.)
If you need a new converter each time, make it a Dictionary<string, Func<ConvertApi>> and populate it as:
{ "txt", () => new Text2PdfConverter() },
{ "doc", () => new Word2PdfConverter() },
... then call the delegate to get the converter when you need it.
Of course, this puts all the initialization in one place - you may want a way of getting the converters to register the extensions they understand with a "converter provider" of some type.
C# supports switch-case operator for strings, i.e. your code coud be rewritten as
switch (fileEx)
{
case "txt" : new Text2Pdf().Convert(file); break;
case "doc": new Word2Pdf().Convert(file); break;
...
}
If you change your classes' names to correspond to supported extensions then you will be able to construct them using reflection, like this (error checking omitted for brevity):
var t = Type.GetType(fileEx + "2Pdf");
var tConstructor = t.GetConstructor(Type.EmptyTypes);
var tInstance = tConstructor.Invoke(new object[0]);
((ConvertApi)tInstance).Convert(...);
This might require some additional work (i.e. create a separate class for each extension, deriving them from some base class - for example Doc2Pdf and Docx2Pdf both deriving from Word2Pdf).
The advantage is that you will not have to touch this part of code anymore. If you're planning to write some interface for plugins then it may come in handy.
The code above also has an assumption that your ConvertApi classes all have default parameterless constuctor.
You need to use an abstract factory pattern, here. All your text converters should derive from a common interface ITextConverter implementing your Convert method. The file extension would be a parameter of your factory. Here is a sample below (typed "on the fly", sometimes copy-pasting code from my sources, so there might be typos. The goal here is to give you a general idea for a flexible implementation).
public interface IFileConverter
{
bool Convert(string filePath);
}
public static class FileConverterFactory
{
public static IFileConverter Create(string extension)
{
extension = type.ToUpper();
Dictionary<string, ConverterConfig> availableConverters = GetConvertersConfig();
if (!availableConverters.ContainsKey(extension))
throw new ArgumentException(string.Format("Unknown extenstion type '{0}'. Check application configuration file.", extension));
ConverterConfig cc = availableConverters[extension];
Assembly runnerAssembly = Assembly.LoadFrom(cc.Assembly);
Type converterType = runnerAssembly.GetType(cc.Class);
IFileConverter converter = (IFileConverter) Activator.CreateInstance(converterType);
return converter;
}
private static Dictionary<string, ConverterConfig> GetConvertersConfig()
{
var configs = (Dictionary<string, ConverterConfig>) ConfigurationManager.GetSection("ConvertersConfig");
return configs;
}
}
public class ConvertersConfigHandler : IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
Dictionary<string, ConverterConfig> converters = new KeyedList<string, ConverterConfig>();
XmlNodeList converterList = section.SelectNodes("Converter");
foreach (XmlNode converterNode in converterList)
{
XmlNode currentConverterNode = converterNode;
ConverterConfig cc = new ConverterConfig();
cc.Type = XML.GetAttribute(ref currentConverterNode, "Type").ToUpper();
cc.Assembly = XML.GetAttribute(ref currentConverterNode, "Assembly");
cc.Class = XML.GetAttribute(ref currentConverterNode, "Class");
converters[cc.Type] = cc;
}
return converters;
}
}
public class ConverterConfig
{
public string Type = "";
public string Assembly = "";
public string Class = "";
}
public class TextConverter : IFileConverter
{
bool Convert(string filePath) { ... }
}
public class PdfConverter : IFileConverter
{
bool Convert(string filePath) { ... }
}
In your app.config file, you add this to the configSections:
<section name = "ConvertersConfig" type = "ConvertersConfigConfigHandler, MyAssembly" />
and this below your configSections:
<ConvertersConfig>
<Converter Type="txt" Assembly="MyAssembly" Class="MyAssembly.TextConverter" />
<Converter Type="pdf" Assembly="MyAssembly" Class="MyAssembly.PdfConverter" />
</ConvertersConfig>
The call would then be like this:
IFileConverter converter = FileConverterFactory.Create("txt");
converter.Convert("c:\temp\myfile");
EDITED the code for giving a solution that is more "generic".
You can use some reflection:
ConvertApi FindMatchingConverter(string _FileExt)
{
//Get all the converters available.
List<ConvertApi> converters = this.GetType()
.Assembly
.GetExportedTypes()
.Where(type => type.IsAssignableFrom(typeof(ConvertApi)))
.ToList();
//Loop and find which converter to use
foreach (var converter in converters)
{
if (converter.SupportedFiles.Contains(_FileExt))
return Activator.CreateInstance(converter);
}
throw new Exception("No converter found");
}
Then you just have to call Convert() on the ConvertApi returned.
Of course, this requires you to add a virtual List<String> named SupportedFiles in your base class.
This makes it look like
public abstract class ConvertApi
{
public abstract void Convert();
public virtual List<String> SupportedFiles {get;set;}
}
What about using a switch?
switch(fileEx){
case "txt": new Text2Pdf().Convert(file); break;
case "doc": new Word2Pdf().Convert(file); break;
}
Use dependency injection where you pass in the supported files in the constructor of the class.
Slower, but more dynamic... use an Object Factory. Here's a good article that seems to fit your needs.
http://www.codeproject.com/Articles/12986/Generic-Object-Factory
The important stuff from the article:
using System.Collections.Generic;
public struct Factory < KeyType, GeneralProduct >
{
//Register a object with the factory
public void> Register< SpecificProduct >(KeyType key)
where SpecificProduct : GeneralProduct, new()
{
if( m_mapProducts == null )
{
m_mapProducts = new SortedList< KeyType, CreateFunctor >();
}
CreateFunctor createFunctor = Creator<SpecificProduct>;
m_mapProducts.Add(key, createFunctor);
}
//Create a registered object
public GeneralProduct Create( KeyType key )
{
CreateFunctor createFunctor = m_mapProducts[ key ];
return createFunctor();
}
private GeneralProduct Creator < SpecificProduct >()
where SpecificProduct : GeneralProduct, new()
{
return new SpecificProduct();
}
private delegate GeneralProduct CreateFunctor();
private SortedList<KeyType, CreateFunctor> m_mapProducts;
}
Usage:
class Fruit
{
}
class Apple : Fruit
{
}
class Orange : Fruit
{
}
class TestClass
{
static void Main(string[] args)
{
General.Factory< string, Fruit > factory;
//Register
factory.Register< Apple >( "Apple" );
factory.Register< Orange>( "Orange" );
//Create
Fruit fruit1 = factory.Create("Apple");
Fruit fruit2 = factory.Create("Orange");
}
}

.NET Serializable entity

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).

Categories

Resources