i am currently working on a project, as the project builds up into lots of lines of code, so i am trying to take the trivial approach and start using some smarter way to make the code be reusable.
so for instance i need to connect to the Sql Server:
(it could be any other task i am learning while i code i am aware of all availble .Net built-in dedicated classes)
really all i need is :
SqlCommand, SqlDataReader (&SqlConnection) and the appropriate container object to return data
usually i am using List<dictionary<string, object>> for my tests with database
so till now it is very minimal i should think.
but, then i say ah that's a good way to connect to sql and fetch some rowsets
then i decide that this is not enough, cause there's some other kinds of returned data, so let's just make some alternative to cover more options, actually let's cover all available scenarios, and then i come up with a class full of "models" covering all available data Formats, single record multiple rows datasets, etc' .
but that's not all there's also 2 main options to read from sql server from .NET
like SqlDataReader And SqlDataAdapter. so i will cover those options too, but wait , there's also the magic words i could use such as stored procedurs and plain text command , so lets make a class that will hold some stractures to define a stored procedure, and then there's storedprocedure parameters, lets make an easy way to call a stored procedure as an object, so later one-line-call and we have a stored procedure object...
now if i will stop right here cause this is yet only the beginning there's much more in that rabbit hole.. and that even was not the best example as the objects created has a very good reason to exist, well unless you want to code it more efficiently you will not create those extra classes and objects
with this behavior and some more tasks to cover on a "daily basis" i begin to see there's a pattern that leads to a huge .Cs file that contains around 10 namespaces with Dozens of classes and functions on each.
the question is how do you decide when to use minimal code and when do you let it go and do not care a lot cause hey, the work station is on say .. 8 cores I7 machine there would not be much of a difference, so lets just worry about the ease of coding.
where do you put the red line ?
Edit the code below is not for a code review purpose, it's just to show the scale of the application and the performance impact it could lead to.**
this is only the core of the data object factory, thats about 1/3 of the class which one of a few in other realted tasks.
public class Inventory
{
public class DataCariers
{
public class DbDataCar
{
public Prototypes.DataCarPrototypes.CarTypeMeta CarierSpec { get; set; }
public AlsDataCariers.Inventory.Compartments.DataCarCompartment Trunk { get; set; }
public string CarierName { get; private set; }
public DbDataCar(AlsTransMods.Direction bsDir, AlsTransMods.CarSize bsCs, AlsTransMods.useCar bsFamType, Compartments.DataCarCompartment bsTrunk)
{
this.CarierSpec = new Prototypes.DataCarPrototypes.CarTypeMeta()
{
CarDirection = bsDir,
carOfSize = bsCs,
CarFamilySelected = bsFamType
};
this.Trunk = bsTrunk;
this.Trunk.Value = new object();
this.Trunk.compTypeMeta.CompartmentParent = this.GetType();
}
public DbDataCar(Prototypes.DataCarPrototypes.CarTypeMeta bsCarierSpec, Compartments.DataCarCompartment bsTrunk)
{
this.CarierSpec = bsCarierSpec;
this.Trunk = bsTrunk;
this.Trunk.Value = new object();
this.Trunk.compTypeMeta.CompartmentParent = this.GetType();
}
internal void SetTunk(string CsvVal)
{
//this.Trunk = new AlsDataCariers.Inventory.Compartments.GenericsDataCarCompartment.Singles(CsvVal);
if (this.CarierSpec.CarDirection == AlsTransMods.Direction.In)
{
// new Compartments.MultipleRowsTabedMultipleRecordsCompartmnet(new prototypesFactory.DataCarPrototypes.selectionsTypeCreator(prototypesFactory.DataCarPrototypes.SelectionMode.selectionMultyRow).SelectedSelectionType);
}
else this.Trunk.Value = new Csv() { val = CsvVal };
}
}
public class GenericDbDataCar : DbDataCar
{
public GenericDbDataCar(AlsTransMods.Direction bsDir, AlsTransMods.CarSize bsCs, AlsTransMods.useCar bsFamType, Compartments.DataCarCompartment bsTrunk)
: base(bsDir, bsCs, bsFamType, bsTrunk)
{
this.CarierSpec = new Prototypes.DataCarPrototypes.CarTypeMeta();
this.CarierSpec.CarDirection = bsDir;
this.CarierSpec.carOfSize = bsCs;
this.CarierSpec.CarFamilySelected = bsFamType;
this.CarierSpec.CarOfType = this.GetType();
base.CarierSpec = this.CarierSpec;
//this.Trunk = this.TrunkCreate();
//base.Trunk = this.Trunk;
}
public GenericDbDataCar(Prototypes.DataCarPrototypes.CarTypeMeta bsCarierSpec, Compartments.DataCarCompartment bsTrunk)
: base(bsCarierSpec, bsTrunk)
{
this.CarierSpec.CarOfType = this.GetType();
base.CarierSpec = this.CarierSpec;
}
}
public class TabularDbDataCar : DbDataCar
{
public TabularDbDataCar(AlsTransMods.Direction bsDir, AlsTransMods.CarSize bsCs, AlsTransMods.useCar bsFamType, Compartments.DataCarCompartment bsTrunk)
: base(bsDir, bsCs, bsFamType, bsTrunk)
{
this.CarierSpec = new Prototypes.DataCarPrototypes.CarTypeMeta();
//this.CarierName = string.Concat(bsCs, bsFamType);
this.CarierSpec.CarDirection = bsDir;
this.CarierSpec.carOfSize = bsCs;
this.CarierSpec.CarFamilySelected = bsFamType;
this.CarierSpec.CarOfType = this.GetType();
base.CarierSpec = this.CarierSpec;
}
public TabularDbDataCar(Prototypes.DataCarPrototypes.CarTypeMeta bsCarierSpec, Compartments.DataCarCompartment bsTrunk):base(bsCarierSpec, bsTrunk)
{
this.CarierSpec.CarOfType = this.GetType();
}
}
}
public class Compartments
{
public class DataCarCompartment
{
//private Prototypes.DataCarPrototypes.selectionsType selectionsType;
public RobCs509b.MyModels.Prototypes.DataCarPrototypes.CompartmentMeta compTypeMeta{get; private set;}
public DataCarCompartment(RobCs509b.MyModels.Prototypes.DataCarPrototypes.CompartmentMeta Bs_CompTypeMeta)
{
this.compTypeMeta = Bs_CompTypeMeta;
this.compTypeMeta.CompartmentSeed = this.GetType();
}
public virtual object Value { get; set; }
}
public class TabularDataCarCompartment : DataCarCompartment
{
public TabularDataCarCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentFamilyType = this.GetType();
}
}
public class TabedSingleRecordComartment : TabularDataCarCompartment
{
public TabedSingleRecordComartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new DataColumn();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
}
public new DataColumn Value;
}
public class TabedMultipleRecordsCompartment : TabularDataCarCompartment
{
public TabedMultipleRecordsCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType= this.GetType();
}
}
public class TabedSingleRowMultipleRecordsCompartment : TabedMultipleRecordsCompartment
{
public TabedSingleRowMultipleRecordsCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
base.Value = this.Value;
}
public new DataRow Value;
}
public class MultipleRowsTabedMultipleRecordsCompartmnet : TabedMultipleRecordsCompartment
{
public MultipleRowsTabedMultipleRecordsCompartmnet(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new DataTable();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
base.Value = this.Value;
}
public new DataTable Value;
}
public class MultipleRowsClonedTabedMultipleRecordsCompartmnet : TabedMultipleRecordsCompartment
{
public MultipleRowsClonedTabedMultipleRecordsCompartmnet(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new ClonedSchemaDtt("NotSet");
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
}
public new ClonedSchemaDtt Value;
}
public class GenericDataCarCompartment : DataCarCompartment
{
public GenericDataCarCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentFamilyType = this.GetType();
}
}
public class GenericSingelRecordCompartment : GenericDataCarCompartment
{
public GenericSingelRecordCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
}
}
public class GenericSingleCsv :GenericSingelRecordCompartment
{
public GenericSingleCsv(string CsvVal,Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
this.Value = new Csv();
this.Value.val = CsvVal;
}
public new Csv Value;
}
public class GenericMultipleRecordsCompartment : GenericDataCarCompartment
{
public GenericMultipleRecordsCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
}
//public RepetablevaluesCollections RepeatbleCollNameVal;
//public UniqCollectionNameval UniqCollNameVal;
}
public class GenericSingleRowMultipleRecordsCompartment3s: GenericMultipleRecordsCompartment
{
public GenericSingleRowMultipleRecordsCompartment3s(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new MyGenericObject3<string, string, string>("", "", "");
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
}
/// <summary>
/// MyGenericObject3 (string,string,string) values.
/// </summary>
public new MyGenericObject3<string, string, string> Value;
}
public class GenericMultipleRowsMyGenericObj3DataCarCompartment:GenericMultipleRecordsCompartment
{
public GenericMultipleRowsMyGenericObj3DataCarCompartment (Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new List<MyGenericObject3<string, string, string>>();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
base.Value = this.Value;
}
/// <summary>
/// DbMagaZine (List MyGenereicObject3) valueType
/// </summary>
public new List<MyGenericObject3<string, string, string>> Value;
}
}
public class CompartmentTypes
{
private CompartmentTypes creator;
public CompartmentTypes ()
{
}
}
}
public class Compartments
{
public class Tabular :Inventory.CompartmentTypes
{
Type CompartmentOfFamilyType = typeof(System.ComponentModel.MarshalByValueComponent);
Type CompartmnetOfType = typeof(Tabular);
}
public class Generic : Inventory.CompartmentTypes
{
Type CompartmnetOfType = typeof(Generic);
}
}
The problem of yours is, that there are so many options to do the same thing.
My advise is to use the technology that is easiest to program and only switch to lower level abstractions if absolutely necessary for perfomance reasons.
And don't compare performance for simple cases but think about the whole system performane and maintenance.
I did database programming in the pre Entity Framework times, and it takes much more expertise and effort to this correctly, so I would not recommend this as of today.
So I reccommend technology in the following order:
Entity Framework pure
Entity Framework with stored procedures for special cases
Datasets and hand crafted logic
Datasets with stored procedures for special cases
SqlDatareader for read only sequential access of a whole table
Related
Imagine a factory that produces objects of a certain type but keeps a WeakReference to them. This factory can tell us how many objects of a particular type are alive. But what if I want to replace every single one of those objects with an entirely different instance, but have every single location in code where this instance is used be automatically updated. How do I do it?
For example, given the following scenario:
public interface ITheme
{
string TextColor { get; }
string BgrColor { get; }
}
class LightTheme : ITheme
{
public string TextColor => "black";
public string BgrColor => "white";
}
class DarkTheme : ITheme
{
public string TextColor => "white";
public string BgrColor => "dark gray";
}
I can construct a tracking factory that simply tracks objects it creates:
public class TrackingThemeFactory
{
private readonly List<WeakReference<ITheme>> themes = new();
public ITheme CreateTheme(bool dark)
{
ITheme theme = dark ? new DarkTheme() : new LightTheme();
themes.Add(new WeakReference<ITheme>(theme));
return theme;
}
public string Info
{
get
{
var sb = new StringBuilder();
foreach (var reference in themes)
{
if (reference.TryGetTarget(out var theme))
{
bool dark = theme is DarkTheme;
sb.Append(dark ? "Dark" : "Light");
sb.AppendLine(" theme");
}
}
return sb.ToString();
}
}
}
If, however, I want to replace every constructed instance, I end up having to create a type with an extra level of indirection
public class Ref<T> where T : class
{
public T Value;
public Ref(T value)
{
Value = value;
}
}
To be used in
public class ReplaceableThemeFactory
{
private readonly List<WeakReference<Ref<ITheme>>> themes
= new();
private ITheme createThemeImpl(bool dark)
{
return dark ? new DarkTheme() : new LightTheme();
}
public Ref<ITheme> CreateTheme(bool dark)
{
var r = new Ref<ITheme>(createThemeImpl(dark));
themes.Add(new(r));
return r;
}
public void ReplaceTheme(bool dark)
{
foreach (var wr in themes)
{
if (wr.TryGetTarget(out var reference))
{
reference.Value = createThemeImpl(dark);
}
}
}
}
This does in fact work:
var factory2 = new ReplaceableThemeFactory();
var magicTheme = factory2.CreateTheme(true);
Console.WriteLine(magicTheme.Value.BgrColor); // dark gray
factory2.ReplaceTheme(false);
Console.WriteLine(magicTheme.Value.BgrColor); // white
But I'm wondering if there's a better way.
Hello i have a very big problem. I need to take/create connection to one core with single type and make any operations.
For now its looks like:
public class SolrMachine<T> : ISolrMachine<T> where T : ISolrRecord
{
private ISolrOperations<T> actuallyInstance { get; set; }
public SolrMachine(string coreName)
{
string url = String.Format("http://xxxx/solr/{0}", coreName);
ISolrConnection solrConnection = new SolrConnection(url) { HttpWebRequestFactory = new SolrAuthWebRequestFactory()};
Startup.Init<T>(solrConnection);
var myInstance = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
this.actuallyInstance = myInstance;
}
}
ISolrMachine<T> is a interface with my methods to operate on solr core. ISolrRecord is a interface with properties in my cores.
Now, when I am doing a connection with two other cores all works perfectly.
SolrMachine<SolrTypeOne> firstCoreConnection = new SolrMachine<SolrTypeOne>(firstCoreName);
SolrMachine<SolrTypeTwo> secondCoreConnection = new SolrMachine<SolrTypeTwo>(secondCoreName);
// operation on firstCoreConnection and secondCoreConnection works
But when I'm trying to connect with one type and one coreName i have exception on Startup.Init<T>(solrConnection). I know that Startup container blocks a connection with same Type and coreName but always I am creating a new instance to this SolrMachine. I expect this:
class SomeClass
{
public MyMethod()
{
SolrMachine<SolrTypeOne> myConn = new SolrMachine<SolrTypeOne>(firstCoreName);
// operation
}
}
class SecondSomeClass
{
public MyMethod()
{
SolrMachine<SolrTypeOne> myConn2 = new SolrMachine<SolrTypeOne>(firstCoreName);
// here it's not work
}
}
How to avoid this ?
In my case, problem was that my Solr using a IHttpWebRequestFactory. From SolrNet multicore documentation author doesn't take this problem. Here is my solution (use Windsor):
public class SolrAuth : IHttpWebRequestFactory
{
public IHttpWebRequest Create(Uri url)
{
//... credentials, timeouts, etc.
return new HttpWebRequestAdapter((HttpWebRequest)webrequest);
}
}
public class SolrMachine<T> : ISolrMachine<T> where T : ISolrRecord
{
public WindsorContainer myContainer = new WindsorContainer();
private ISolrOperations<T> actuallyInstance { get; set; }
public SolrMachine(string coreName)
{
var url = string.Format("http://xxx/solr/{0}", coreName);
myContainer.Register(Component.For<IHttpWebRequestFactory>().ImplementedBy<SolrAuth>());
var solrFacility = new SolrNetFacility(string.Format("http://xxx/solr/{0}", "defaultCollection"));
solrFacility.AddCore(coreName, typeof(T), url);
myContainer.AddFacility(solrFacility);
this.actuallyInstance = myContainer.Resolve<ISolrOperations<T>>();
}
}
I might have coded myself into a corner here, but I am hoping there is a simple way out of it.
My Logic Layer is a static singleton instance that has lots of properties for accessing the individual sub-Logic Layers. Most of this was put in place for unit testing to allow injection of custom repositories and works quite nicely for that. However the boiler plate code for each sub-instance is very repetitive and I would expect that there is a way to simplify it.
Below is a very simplified example to demonstrate how far I have manages to get and where I am stuck. The one way that works is with an indexer on the sub-logic class wrapper to get to the sub-logic, which reads very strangely. The other way is by using a random letter as a property on the sub-logic class wrapper to get to the sub-logic. This reads slightly better, but still has a ripple effect on all the existing code.
Can this be done the way I want to, or should I be looking at this completely differently.
Apologies for the length of the example. I tried to make it as simple as possible while still keeping the concept intact
class Program
{
static void Main(string[] args)
{
var logic = new Logic();
// old usage (desired)
var abcs_1 = logic.ABCs_1.List();
var defs_1 = logic.DEFs_1.List();
// new usage (would like to keep old way)
var abcs_2 = logic.ABCs_2[0].List(); // <-- ugly
var defs_2 = logic.DEFs_2.d.List(); // <-- less ugly, but still not pretty
//var abcs_2 = logic.ABCs_2.List(); // <-- wanted
//var defs_2 = logic.DEFs_2.List(); // <-- wanted
}
}
public class ABC { }
public class DEF { }
public class ABCsLogicLayer
{
public List<ABC> List() { return null; }
}
public class DEFsLogicLayer
{
public List<DEF> List() { return null; }
}
public class Logic
{
#region New Code. Want to move towards this
public LogicLocker<ABCsLogicLayer> ABCs_2 = new LogicLocker<ABCsLogicLayer>();
public LogicLocker<DEFsLogicLayer> DEFs_2 = new LogicLocker<DEFsLogicLayer>();
#endregion
#region Old Code. Want to move away from this.
#region BuilerPlate for ABCs_1
private ABCsLogicLayer m_ABCs = null;
private readonly object m_ABCsLock = new object();
public ABCsLogicLayer ABCs_1
{
get
{
lock (m_ABCsLock)
{
if (m_ABCs == null)
{
m_ABCs = new ABCsLogicLayer();
}
}
return m_ABCs;
}
set
{
lock (m_ABCsLock)
{
m_ABCs = value;
}
}
}
#endregion
#region BuilerPlate for DEFs_1
private DEFsLogicLayer m_DEFs = null;
private readonly object m_DEFsLock = new object();
public DEFsLogicLayer DEFs_1
{
get
{
lock (m_DEFsLock)
{
if (m_DEFs == null)
{
m_DEFs = new DEFsLogicLayer();
}
}
return m_DEFs;
}
set
{
lock (m_DEFsLock)
{
m_DEFs = value;
}
}
}
#endregion
#endregion
}
public class LogicLocker<T> where T : class, new()
{
private T LogicLayer = null;
private readonly object LogicLayerLock = new object();
public T this[int i]
{
get
{
lock (LogicLayerLock)
{
if (LogicLayer == null)
{
LogicLayer = new T();
}
}
return LogicLayer;
}
set
{
lock (LogicLayerLock)
{
LogicLayer = value;
}
}
}
public T d
{
get
{
lock (LogicLayerLock)
{
if (LogicLayer == null)
{
LogicLayer = new T();
}
}
return LogicLayer;
}
set
{
lock (LogicLayerLock)
{
LogicLayer = value;
}
}
}
}
You can use interface for solve your problem:
1) Define interface with List method:
public interface ILogicLayer<T>
{
List<T> List();
}
2) Your logic layer class should implement this interface:
public class ABCsLogicLayer:ILogicLayer<ABC>
3) LogicLocker should implement this interface as well
public class LogicLocker<T,U> : ILogicLayer<U> where T : ILogicLayer<U>, new()
Implementation of List method will be:
lock (LogicLayerLock)
{
if (LogicLayer == null)
{
LogicLayer = new T();
}
}
return LogicLayer.List();
4) You will instantiate your logic locker in the Logic class
public LogicLocker<ABCsLogicLayer, ABC> ABCs_2 = new LogicLocker<ABCsLogicLayer,ABC>();
public LogicLocker<DEFsLogicLayer, DEF> DEFs_2 = new LogicLocker<DEFsLogicLayer, DEF>();
or better make it more generics:
public LogicLocker<LogicLayer<ABC>> ABCs_2 = new LogicLocker<LogicLayer<ABC>>();
but it depends on what you want
Is it possible to mark a property in base class with some attribute that remains effective in child classes too?
Question might be very specific to Serialization, but I definitely think there can be other uses as well.
Consider the following code:
using System;
using System.IO;
using System.Xml.Serialization;
namespace Code.Without.IDE
{
[Serializable]
public abstract class C1
{
[XmlIgnore]
public abstract bool IsValid_C1 { get; set;}
}
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
public override bool IsValid_C1 { get; set;}
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
public static class AbstractPropertiesAttributeTest
{
public static void Main(string[] args)
{
C2 c2 = new C2();
using(MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = new XmlSerializer(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
}
}
Above code returns:
------ C:\abhi\Code\CSharp\without IDE\AbstractPropertiesAttributeTest.exe
<?xml version="1.0"?>
<C2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IsValid_C2>false</IsValid_C2>
<IsValid_C1>true</IsValid_C1>
</C2>
------ Process returned 0
I thought IsValid_C1 will be ignored, though it is not so. Is there any way of achieving this other than marking the property as protected?
Edit: A quick code to show that XmlIgnore attibute is being inherited.
http://ideone.com/HH41TE
I don't believe there is a way to inherit the attribute since you override the base class property. You would need to decorate the IsValid_C1 of C2 with XmlIgnore:
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
[XmlIgnore]
public override bool IsValid_C1 { get; set; }
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
I will offer a different view of this question. Maybe you just used those properties as an example and want to have severall properties to be cascaded. But i think that this may be a good time to think about the inheritance model proposed.
Basicly you can use regular inheritance or think about some Design Pattern, that can not just solve you issue related to the serialization, but may offer you some more "loose coupling" in you application, making it in a more component model and allowwing each class to deal only with what is concern, this way you can re-use lots of stuff and make your life easier.
Based on that thinking im providing you a sample of the Decorator Design Pattern mixed with the Strategy Design Pattern. If i were developing classes like the ones on your sample, this is how i would do it:
/// <summary>
/// The interface for validation strategy (since we are using interface, there is no need for another abstract class)
/// </summary>
public interface IValidation
{
bool IsValid { get; set; }
}
/// <summary>
/// The decorator (it dont need to be abstract) that has the serializable properties
/// </summary>
[Serializable]
public class ValidatableDecorator : IValidation
{
protected IValidation instance;
public ValidatableDecorator()
{
Init();
}
public ValidatableDecorator(IValidation instance)
{
Init();
}
protected virtual void Init() { }
public void Set(IValidation instance)
{
this.instance = instance;
}
[XmlIgnore]
public bool IsValid
{
get
{
return instance.IsValid;
}
set
{
instance.IsValid = value;
}
}
}
Then you need to implement some classes that have the logic of the strategy Pattern, like this:
public class BossValidatorImplementation : IValidation
{
public bool IsValid
{
get
{
return false; ;
}
set
{
throw new InvalidOperationException("I dont allow you to tell me this!");
}
}
}
public class EasyGoingValidator : IValidation
{
public bool IsValid { get; set; }
}
Now that we have the logic separated from the class, we can inherit from the decorators, choosing wich strategy they use to the IsValid field, like this:
public class ChildWithBossValidation : ValidatableDecorator
{
protected ChildWithBossValidation(IValidation instance)
: this()
{
Init();
}
public ChildWithBossValidation()
: base(new BossValidatorImplementation())
{
Init();
}
protected override void Init()
{
Name = "I'm the boss!";
Sallary = 10000d;
}
public string Name { get; set; }
public double Sallary { get; set; }
}
public class ChildWithEasyGoingValidation : ValidatableDecorator
{
public ChildWithEasyGoingValidation()
: base(new EasyGoingValidator())
{
}
protected ChildWithEasyGoingValidation(IValidation instance)
: this()
{
}
protected override void Init()
{
Name = "Do as you please... :) ";
}
public string Name { get; set; }
}
This is the code to show that the solution works:
public static void Main(string[] args)
{
var boos = new ChildWithBossValidation();
var coolGuy = new ChildWithEasyGoingValidation();
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(boos.GetType());
ser.Serialize(ms, boos);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.WriteLine("-------------");
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(coolGuy.GetType());
ser.Serialize(ms, coolGuy);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.ReadKey();
}
The result is:
{<?xml version="1.0"?>
<ChildWithBossValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>I'm the boss!</Name>
<Sallary>10000</Sallary>
</ChildWithBossValidation>-------------------<?xml version="1.0"?>
<ChildWithEasyGoingValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Do as you please... :) </Name>
</ChildWithEasyGoingValidation>}
So, maybe this does not answer how to cascade the Attribute in this case (because you can easily do it by creating your own attribute(marking to allow inheritance) and then implementing some code to SerializeXML). This is just another option that can improve overall architecture of solutions using Design Pattern. But this solve this particular issue also :)
A needed behaviour can be achieved using classes XmlAttributeOverrides and XmlAttributes. I've written helper method for XmlSerializer creation:
public static XmlSerializer GetXmlSerializerWithXmlIgnoreFields(Type t)
{
XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();
foreach (var prop in t.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
Attribute xmlIgnoreAttribute = Attribute.GetCustomAttribute(prop, typeof(XmlIgnoreAttribute));
if (xmlIgnoreAttribute == null)
continue;
XmlAttributes xmlAttributes = new XmlAttributes();
xmlAttributes.XmlIgnore = true;
xmlOverrides.Add(t, prop.Name, xmlAttributes);
}
return new XmlSerializer(t, xmlOverrides);
}
The Main method became:
public static void Main(string[] args)
{
C2 c2 = new C2();
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = GetXmlSerializerWithXmlIgnoreFields(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
It appears this feature is broken in C#.
You could write an attribute which through reflection will bring down the attributes for you. Pretty straight forward if you understand reflection.
I have the situation below. Is there a simple way to design this so that the data member sample is shared among all instantiations of ChildClass1 and a separate instance of it is shared with all instances of ChildClass2?
abstract class BaseClass{
int sample = 0;
}
class ChildClass1: BaseClass{
}
class ChildClass2: BaseClass{
}
I'm hoping to produce the following
ChildClass1 a = new ChildClass1();
ChildClass1 b = new ChildClass1();
ChildClass2 c = new ChildClass2();
a.sample = 10;
//a.sample = 10, b.sample = 10, c.sample = 0
Maybe this does, what you want:
public abstract class BaseClass
{
public abstract int Sample { get; set; }
}
public class ChildClass1 : BaseClass
{
private static int mSample = 0;
public override int Sample
{
get { return mSample; }
set { mSample = value; }
}
}
public class ChildClass2 : BaseClass
{
private static int mSample = 0;
public override int Sample
{
get { return mSample; }
set { mSample = value; }
}
}
class Program
{
static void Main(string[] args)
{
var a = new ChildClass1();
var b = new ChildClass1();
var c = new ChildClass2();
a.Sample = 10;
Console.WriteLine(a.Sample); // 10
Console.WriteLine(b.Sample); // 10
Console.WriteLine(c.Sample); // 0
}
}
As I said in my comment, I think there is an inherent flaw in your design, but for the sake of providing an answer, you could achieve it like this:
abstract class BaseClass<TDERIVED>
{
private static Dictionary<Type, int> sampleDictionary_ = new Dictionary<Type, int>();
public BaseClass()
{
} // eo ctor
public int Sample
{
get
{
return sampleDictionary_.ContainsKey(typeof(TDERIVED)) ? sampleDictionary_[typeof(TDERIVED)] : 0;
}
set
{
sampleDictionary_[typeof(TDERIVED)] = value;
}
}
}
class ChildClass1 : BaseClass<ChildClass1>
{
}
class ChildClass2 : BaseClass<ChildClass2>
{
}
This has the added advantage that if you add any other Child classes, they will get their own version of the response. Note that this is not thread-safe, and so if you do choose this solution and want to use it in a multi-threaded environment, you might want to put some thread-safety code in place.
You may want to look into the singleton pattern.
Create a class as a singleton to hold the shared data. Then have all three classes reference the singleton.