I'm writing a piece of code to make certain reports. There are 4 types of reports which the user can request. Each type report is based on the base class 'report'. Each derived class has a List. The class 'A' is derived from base class 'a'.
Is it possible to add an abstract List to the 'report' class and let it be overridden by a List in the derived report classes? Something like this?
public abstract class Report
{
public abstract List<a> Coils { get; set; }
}
public class ProductionExitCoilReport : Report
{
public override List<A> Coils { get; set; }
}
public class a
{
public string SomeProperty { get; set; }
}
public class A: a
{
public string SomeOtherProperty { get; set; }
}
I'm kind of new to C# so if I'm asking something really basic or I have a big flaw in my thinking, please do point it out. But please don't just answer with yes or no.
Based on your description of the usage, there is no need to override the List/collection in your new class. Since A inherits from a, you can store objects of type A in "Coils". (due to polymorphism). Then if, at some later time, you want to access "SomeOtherProperty" of the objects of type A, you could use a cast.
public abstract class Report
{
public List<a> Coils { get; set; }
}
public class ProductionExitCoilReport : Report
{
}
public class a
{
public string SomeProperty { get; set; }
}
public class A : a
{
public string SomeOtherProperty { get; set; }
}
public void SomeMethod()
{
//to store the coil
ProductionExitCoilReport myReport = new ProductionExitCoilReport();
myReport.Coils.Add(new A());
//to retreive SomeOtherProperty from the first element in the list
string retrievedProperty = ((A)myReport.Coils[0]).SomeOtherProperty;
}
Your properties are readable and writable.
Derived types must always be compatible with the base type.
Every Report has Coils property that returns a read/write collections of items of type a. Thus you can always write report.Coils.Add(new a()).
ProductionExitCoilReport inherits from Report, so it would have been possible to run the same code - to add a (not A) to the collection returned by Coils: ((Report)productionReport).Coils.Add(new a()).
This contradicts what you want to accomplish.
Please read about covariance and contravariance:
Related
I have a generic class with a single argument that represents an Element of a third party DLL for the purpose of serialization of objects of T kind. What I would like to do is add a 'Dirty' map to my class and lazily trigger it whenever one of my Element's nested properties are changed.
Is it possible to when the property is accessed catch the request and identify what property is changing? That if a SET is being performed I can log that sub-property P is now dirty and needs to be saved? Or at least a single bit that indicates that SOMETHING has changed?
public class ResourceSerializer<T>
where T : Base, new()
{
T element;
Dictionary<String,Boolean> dirtyMap;
public T Element { get { return this.getElement(); } }
public Boolean IsDirty { get; private set; }
public ResourceSerializer()
{
dirtyMap = new Dictionary<string,bool>();
element = new T();
// code to reflect back upon T's Properties and build out the dirtyMap.
// I already can do this I just omitted it.
// in my Person example there would be keys: 'FirstName', 'LastName', 'Age', 'Gender', 'PrimaryAddress'
}
// how can I call this programmatically?
void flagDirty(String property)
{
dirtyMap[property] = true;
this.IsDirty = true;
}
T getElement()
{
// In case I need to do a thing before returning the element.
// Not relevant to the question at hand.
return this.element;
}
}
a somewhat advanced example of 'Base'. You can see how I need to recurse my actions as not everything is a primitive. I have a manager level class that logs all of these ResourceSerializer objects.
public class Base
{
public Base()
{
}
}
public enum gender
{
Male,
Female,
Other,
Unspecified,
}
public class Address : Base
{
public String Street { get; set; }
public String State { get; set; }
public String Zip { get; set; }
public Address() : base()
{
}
}
public class Person : Base
{
public String FirstName { get; set; }
public String LastName { get; set; }
public Int16 Age { get; set; }
public gender Gender { get; set; }
public Address PrimaryAddress { get; set; }
public Person() : base()
{
}
}
public class Patient : Person
{
public Person PrimaryContact { get; set; }
public Patient() : base()
{
}
}
and a small class i would turn into a test method later..
public class DoThing
{
public DoThing()
{
ResourceSerializer<Person> person = new ResourceSerializer<Person>();
person.Element.Age = 13; // catch this and mark 'Age' as dirty.
}
}
Without a custom setter no, there's nothing to do that.
The usual pattern for what you're trying to do is implement the INotifyPropertyChanged interface, that interface is precisely created for classes (or structs) which need to track and inform about changes on their properties.
If you're lazy as me, I would create an analyzer which at the beginning of my app scans all my classes which are tagged with an attribute and with all properties created as virtual, then using codedom I would create a new class which would inherit from the found class and it implements the INotifyPropertyChanged, then you can have a generic Factory which returns instances of these new classes when the type of the generic call is of a known registered type.
I've used this before for classes which I wanted to have remote properties, just tagged the class and my scan system rewrote the getter/setter to do the remote calls transparently, the concept at the end is the same.
It's a lot of work at the begining, but if you have a ton of classes it will be a lot less of code to write than implementing INotifyPropertyChanged on all your classes.
I am using EF code first to generate my db and I do need concrete property for ICollection of EF entity models. I am writing a data access layer ( Using generic classes) however hit the following road block with using interfaces in my generic class as shown below.
public interface ITestClassProp
{
int Value { get; set; }
}
public class TestClassProp : ITestClassProp
{
public int Value { get; set; }
}
public interface ITestClass
{
ICollection<ITestClassProp> TestProp { get; set; }
}
public class TestClass : ITestClass
{
// works
//public ICollection<ITestClassProp> TestProp { get; set; }
// does not work
public ICollection<TestClassProp> TestProp { get; set; }
}
Am I totally mis using the interfaces? why cant I use TestClassProp instead of ITestClassProp?
Thanks
When you implement an interface, you have to implement the methods/properties of that interface with the same signature. Since the interface declares ICollection<ITestClassProp> TestProp { get; set; } then your TestClass must also declare ICollection<TestClassProp> TestProp { get; set; }.
The reason this is necessary is that other classes that know about the interface but not the concrete class are expecting the property to be ICollection<ITestClassProp> and not ICollection<TestClassProp>.
As you've currently written your code, you are not satisfying the requirement you've imposed via your ITestClass interface, which is to have a property of ICollection<ITestProp>.
One way around this is to actually make ITestClass generic, but provide a generic constraint of ITestClassProp
public interface ITestClassProp
{
int Value { get; set; }
}
public class TestClassProp : ITestClassProp
{
public int Value { get; set; }
}
public interface ITestClass<T> where T : ITestClassProp
{
ICollection<T> TestProp { get; set; }
}
public class TestClass : ITestClass<TestClassProp>
{
public ICollection<TestClassProp> TestProp { get; set; }
}
This allows you to provide any concrete type that implements ITestProp to your ICollection.
Simply, the interface declares a property of type ICollection, but you implement it as ICollection, which has a totally different signature.
You might want to read up on covariance and contravariance also.
I have made a generic class like below:
public abstract class ListCoreDTO<T=int, P=int, G=int, S=int>
{
public T Value { get; set; }
public string Text { get; set; }
public P ParentID { get; set; }
public G Group { get; set; }
public string DetailsInfo { get; set; }
public S SerialNo { get; set; }
}
Here I want calling my generic class like below:
public class ListGenericDTO : ListCoreDTO<T:int, S:long>
{
}
How can I make this type of generic class and my calling class?
As I understand the question, you want to create another generic type which uses some arguments fix and some variable.
When I'm correct, your class signature should look like this
public class ListGenericDTO<P, G> : ListCoreDTO<int, P, G, long>
So the ListCoreDTO-type gets typed with intfor T and long for S.
There is no such thing as an optional generic argument. This is a limitation of the language an something you simply need to workaround.
One way to do such a workaround is to implement inherited classes which fix the generic argument one way or another (see answer from Patrik Eckebrecht). This will allow you to call the generic class as if it had optional arguments, although it will behave with the semantics of a derived class when it comes to using the types.
I have a scenario with a domain model used with NHibernate which looks kind of as below.
public class BaseClass
{
public virtual int Id { get; set; }
public virtual string SomeProperty { get; set; }
}
public class FirstClass : BaseClass
{
public virtual IList<AnotherClass> AnotherClassList { get; set; }
}
public class SecondClass : BaseClass
{
public virtual AnotherClass AnotherClass { get; set; }
}
public class AnotherClass
{
public virtual int Id { get; set; }
public virtual BaseClass MyNavigationalProperty { get; set; }
}
It look nice but it does not work as I was expecting it would do. This is my scenario;
As my first step I am saving my FirstClass with one or many AnotherClass in the list and it works perfectly. I could retrieve my FirstClass with my related AnotherClasses in the list.
In my second step I am saving a new AnotherClass separately and sets MyNavigationalProperty to my FirstClass from my first step. It do looks great, but...
In my final step I am retrieving my FirstClass and I am expecting that my AnotherClassList contains the AnotherClass from my second step. But I only get the original AnotherClasses from my first step.
Looking into the database I can see the record from my second step but there are two separate FKs in the table AnotherClass, BaseClass_Id and FirstClass_Id, and FirstClass_Id is NULL and therefore I don't get this record in my final step.
Is this wrong way to implement navigational properties? And, if so, how should I do it properly? Or... simply, is there a better way of doing this?
EDIT
From the question of mappings of Thilak I got another thought, The original domain model did not make use of a BaseClass, that is my implementation. Would that make it necessary to create my own mappings? Would that mean I have to totally abandon the automapping?
the reference uses another column as the collection. you can override it manually
class SetForeignKeyColumn : IAutomappingOverride<FirstClass>
{
public ...
{
instance.HasMany(x => x.AnotherClassList).KeyColumn("baseclass_id");
}
}
I have a system that performs operations on lots of Things, these can be considered to be hardware devices accessible over a communication channel.
I use a manager construct that accepts tasks for single Things. Now, there are at least three types of Thing and they have slightly different properties associated with them. The manager must know about these extra properties as they are needed to perform any operation correctly (some Things must have their X foo'd instead of their Y etc...).
At the moment I have separate manager class for each type of thing. This causes a good deal of duplication as the Things are mostly similar.
It would be good if I could have an abstract manager that implements a good deal of the functionality and then each concrete implementation can supply the little extra bits.
Here is a greatly simplified example:
public abstract class ThingManager
{
private ConcurrentDictionary<Guid, ??ThingTask??> _ThingTaskQueue;
public virtual AddNewThingTask(<params>)
{
??ThingTask?? NewTask = new ??ThingTask??(<params>);
_ThingTaskQueue.Add(NewTask);
Monitor.Pulse(_NewDataToProcess);
}
/* Implemented by the concrete, will depend on the type of ??ThingTask?? */
public abstract GetSomeTaskParameterForAThing(Guid thingID)
}
public class ThingTask
{
public enum ThingOperation
{
Foo,
Bar
};
public String Name { get; set; };
public ThingType Type { get; set; };
public ThingOperation Operation { get; set; }
}
public class AdvancedThingTask
{
public enum ThingOperation
{
Foo,
Bar,
Baz
};
public String Name { get; set; };
public ThingType Type { get; set; };
public ThingOperation Operation { get; set; }
public Boolean EnableFrobber { get; set; }
}
As you can see I need some way, when defining the concrete ThingManager to have ??ThingTask?? be either a ThingTask or an AdvancedThingTask. It would then be up to the concrete to make use of the extra properties when implementing the abstract methods.
Using an interface for ??ThingTask?? wouldn't work because the properties would have to be declared in the interface and each one has different properties available.
I get the feeling I'm missing something very obvious as to how to do this cleanly, hopefully someone can help :)
use generics rather than a pure abstract class, someting along the lines of:
public abstract class ThingManager<T> where T : ThingTask
dependant on your full implementation I doubt if this will need to remain abstract
Is there any reason you don't make AdvancedThingTask a subclass of ThingTask?
public class ThingTask
{
public virtual string Name { get; set; }
public virtual ThingType Type { get; set; }
public virtual ThingOperation Operation { get; set; }
public virtual void DoThing() { /*Do something associated with ThingTask*/ }
}
public class AdvancedThingTask : ThingTask
{
public bool EnableFrobber { get; set; }
public override void DoThing() { /*Do something associated with AdvancedThingTask*/ }
}
The only problem I see with this is that ThingOperation will need to be declared outside of the classes so that it can have all the values, or some other solution that will enable classes to have values that aren't in the base declaration. That problem may be solved by putting what you want to do as virtual methods in the classes.
P.S. Why do your properties start with underscores? Usually that's reserved for private variables.