I want to create a class that could hold any of a number of same type of classes. For example lets says I have a base class like follows:
public class BaseClass
{
public string MyBaseString
{
get;
set;
}
}
And then I have a few derived classes like this:
public class DerivedClass : BaseClass
{
public MyDerivedClassString
{
get;
set;
}
}
public class DerivedClass2 : BaseClass
{
public MyDerivedClass2String
{
get;
set;
}
}
Now I would like a class that accepts one of these implementations and does stuff with it. Here is the only thing I can think of, but there must be a better way:
public class ClassA
{
public object MyClass
{
get;
set;
}
public ClassA (object myClass)
{
MyClass = myClass;
if (object is BaseClass)
{
//do something
}
else if (object is DerivedClass)
{
//do something specific to derived class
}
else if (object is DerivedClass2)
{
//do something specific to derived class 2
}
}
}
CLARIFICATION: The specific goal I am trying to accomplish is to use ClassA as a container class for various implementations of the BaseClass. The business goal I am trying to accomplish is to create a Legend object which might use multiple color schemes (i.e. a Mono Color Ramp, Multi Color Ramp, etc). So I would like the Legend class to contain the ColorScheme that is being used, but still have access to that color scheme's unique properties for modification later on.
CLARIFICATION 2 Based on the wide array of responses I got, I thought I'd provide an exact replication of what I'm trying to do:
public class BaseColorScheme
{
List<Color> _colors = new List<Color>();
public List<Color> Colors
{
get
{
return _colors;
}
set
{
_colors = value;
}
}
}
public class SingleColorScheme : BaseColorScheme
{
public Color MidColor
{
get;
set;
}
public SingleColorScheme( Color midColor, int numberOfClassifications )
{
Colors = CreateMonoColorRamp( midColor, numberOfClassifications );
}
}
public class MultiColorScheme : BaseColorScheme
{
public Color StartColor
{
get;
set;
}
public Color EndColor
{
get;
set;
}
public Color MidColor
{
get;
set;
}
public MultiColorScheme( Color startColor, Color endColor, Color midColor )
{
StartColor = startColor;
EndColor = endColor;
MidColor = midColor;
Colors = //do something to define multi color scheme
}
}
Then I would have a Legend Class that would be something like
public class Legend
{
public object ColorScheme
{ get; set; }
public Guid LegendId
{ get; set; }
public Legend(object colorScheme)
{
ColorScheme = colorScheme;
}
}
Finally I might have a form that sits on top of the legend that displays the properties of the various color schemes based on which type of color scheme it is. Hopefully that helps clarify a bit.
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
}
Beyond that, define the common interface of the class hierarchy either as an interface or as methods (concrete, abstract, or virtual) within the base class. Then you can be assured all derived classes have such method / properties and can use them within your generic wrapper.
Instead of letting ClassA perform whatever needs to be done, you can use polymorphism and let the classes do it to themselves.
Simply declare a virtual method in the base class, have it do whatever you need it do so, and then override this method in the subclasses. In the method in ClassA, you just need to call that method on the object you receive as a parameter - without having to care about the specific type.
If you need to access different properties based on which derived class is passed something like this should help:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
public void DoStuffToMyClass()
{
if(MyClass is BaseClass)
{ // do base class stuff }
else if(Myclass is DerivedClass)
{ // do DerivedClass stuff }
else if(MyClass is DerivedClass2)
{ // do DerivedClass2 stuff }
}
}
This gives you the type saftey to ensure you at least have the BaseClass object, and possibly a derived class.
The answer is polymorphism, let the object do it themselves.
public class BaseClass
{
public string MyString { get; set; }
public virtual string DoIt()
{
return "I'm Base Class";
}
}
public class DerivedClassA
{
public override string DoIt()
{
return "I'm Derived Class A";
}
}
public class DerivedClassB
{
public override string DoIt()
{
return "I'm Derived Class B";
}
}
....
public ClassA (BaseClass myClass)
{
MyClass = myClass;
MyClass.DoIt();
}
.....
ClassA x1 = ClassA(new BaseClass()) // calls BaseClass.DoIt()
ClassA x2 = ClassA(new DerivedClassA()) // calls DerivedClassA.DoIt()
ClassA x3 = ClassA(new DerivedClassB()) // calls DerivedClassB.DoIt()
whenever you catch yourself acting differently based on the run-time type of the object, you are dealing with code that breaks OO principles, i.e. a class that does not respect the base class contract.
Can you use virtual methods?
public abstract class BaseClass
{
public abstract void DoStuff();
}
public class DerivedClass1 : BaseClass
{
public override void DoStuff()
{
...
}
}
public class DerivedClass2 : BaseClass
{
public override void DoStuff()
{
...
}
}
Without generics:
public class ClassA
{
public BaseClass MyClass
{
get;
set;
}
public ClassA (BaseClass myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
or with generics:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA (T myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
Keep it simple: polymorphism
Hopefully your objects have a common interface, something like:
class Base {
public virtual void DoSomething() { /* Default implementation */ }
}
class Derived1 : Base {
public override void DoSomething() { /* Implementation specific to this type */ }
}
class Derived2 : Base {
public override void DoSomething() { /* Another implementation specific to this type */ }
}
Or maybe they implement a common interface. So hopefully your consuming class can hold the most general representation of your inputs as possible and invoke code as such:
class Dependent {
public Dependent(Base instance) {
instance.DoSomething();
}
}
So your Dependent class doesn't really are whether it has a derived type or a base type.
Not quite as simple: visitor pattern
Sometimes polymorphism doesn't really work, which is particularly the case if you need to access the specific members of your derived classes, and those members aren't in the base class. Visitor pattern works well in this case, especially if you have a fixed, well-defined graph of objects.
public interface IVisitor<T> {
T Visit(Base x);
T Visit(Derived1 x);
T Visit(Derived2 x);
}
class Base {
public virtual T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string BaseString { get; set; }
}
class Derived1 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived1String { get; set; }
}
class Derived2 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived2String { get; set; }
}
So Derived1 and Derived2 have a different set of properties, and if you need to get to those properties without a runtime type-checking, implement a visitor:
class DefaultStringVisitor : IBaseVisitor<string> {
public string Visit(Base x) { return x.BaseString; }
public string Visit(Derived1 x) { return x.Derived1String; }
public string Visit(Derived2 x) { return x.Derived2String; }
}
class Dependent {
public Dependent(Base x) {
string whatever = x.Accept<string>(new DefaultStringVisitor());
}
}
So the visitor pattern gives you access to your derived object's members without a type-check. Its a somewhat inflexible pattern (i.e. need to know which objects to visit up front), but it might work for your needs.
Related
Struggling with wording that title to make any sense so I will just show my code and try and explain it
So I have this base class
public abstract class SpacecraftProperty
{
}
public abstract class SpacecraftProperty<T> : SpacecraftProperty
where T : SpacecraftProperty<T>
{
public abstract void Add(T property);
}
With this I can create a collection of SpacecraftProperty just fine thanks to the base SpacecraftProperty class that is not generic.
Then I have this class that derives from SpacecraftProperty that is also generic
public class ResourceStorage<ResourceType> : SpacecraftProperty<ResourceStorage<ResourceType>>
where ResourceType : ResourceInfo, new()
{
public ResourceType resource { get; private set; } = new ResourceType();
public float capacity { get; private set; }
public override void Add(ResourceStorage<ResourceType> property)
{
this.capacity += property.capacity;
}
}
Now the issus is that I need to create a collection of this ResourceStorage class, where each object in the collection can be of any type for ResourceType. But I can't use the same trick as above where I create a non-generic base class as then when I try and derive from SpacecraftProperty<>, it won't know what type of the generic SpacecraftProperty to derive from.
For completeness, here is the code for ResourceInfo, which is an abstract class which will be derived from
public abstract class ResourceInfo
{
public abstract string GetName();
public abstract string GetDescription();
}
So in summary I would for example want a collection that contains say a ResourceStorage<SomeTypeA>, ResourceStorage<SomeTypeB> etc. where SomeTypeA and SomeTypeB derive from ResourceInfo. And ResourceStorage derives from SpacecraftProperty, which has the generic method Add.
Any ideas?
But I can't use the same trick as above where I create a non-generic base class as then when I try and derive from SpacecraftProperty<>, it won't know what type of the generic SpacecraftProperty to derive from.
You can use the same trick. The type to derive from is SpacecraftProperty<ResourceStorage>, where ResourceStorage is the non-generic type you have created. This is because the implementation of Add in the generic ResourceStorage<T> doesn't actually use T.
// note that I've changed the naming conventions to match that of C#'s
public abstract class ResourceStorage: SpacecraftProperty<ResourceStorage> {
public abstract float Capacity { get; protected set; }
}
public class ResourceStorage<TResource> : ResourceStorage
where TResource: ResourceInfo, new()
{
public TResource Resource { get; private set; } = new TResource();
public override float Capacity { get; protected set; }
public override void Add(ResourceStorage property)
{
Capacity += property.Capacity;
}
}
ResourceStorage<TResource> is now a SpacecraftProperty<ResourceStorage>, however, and not a SpacecraftProperty<ResourceStorage<TResource>>.
To fix that, you can make the abstract classes contravariant interfaces instead. Since there is only one Add method:
public interface ISpacecraftProperty {}
public interface ISpacecraftProperty<in T> : ISpacecraftProperty
where T : ISpacecraftProperty<T>
{
void Add(T property);
}
public interface IResourceStorage: ISpacecraftProperty<IResourceStorage> {
public float Capacity { get; }
}
public class ResourceStorage<TResource> : IResourceStorage
where TResource: ResourceInfo, new()
{
public TResource Resource { get; private set; } = new TResource();
public float Capacity { get; private set; }
public void Add(IResourceStorage property)
{
Capacity += property.Capacity;
}
}
Now this compiles:
var list = new List<IResourceStorage>() {
new ResourceStorage<Foo>(),
new ResourceStorage<Bar>()
};
// This'd work too, but I'm sure you are aware already, since it is the nature of what you are trying to do
list[0].Add(list[1]);
ISpacecraftProperty<ResourceStorage<Foo>> x = new ResourceStorage<Foo>();
If ISpacecraftProperty has other methods that return a T, and so can't be contravariant, you can always just add ISpacecraftProperty<ResourceStorage<TResource>> as yet another interface of ResourceStorage<TResource>.
public class ResourceStorage<TResource> : IResourceStorage, ISpacecraftProperty<ResourceStorage<TResource>>
where TResource: ResourceInfo, new()
{
public TResource Resource { get; private set; } = new TResource();
public float Capacity { get; private set; }
public void Add(IResourceStorage property)
{
Capacity += property.Capacity;
}
// implement explicitly by delegation
void ISpacecraftProperty<ResourceStorage<TResource>>.Add(ResourceStorage<TResource> property) {
Add(property);
}
}
Hi after failing with inheritance (it got complicated) I stumble onto Generics. I am new to coding in general and C# is my first language.
I have two classes CIMTDXInput, RMTTDXInput which have the same properties but those properties have slightly different members. For those same 3 properties between the two, I want to just check if they are null or not.
So I wrote this:
public static TDX2KlarfResult CheckCIMTDXInput <T> (T input, TDX2KlarfResult result) where T: CIMTDXInput, RMTTDXInput
{
if (input.ToolContext == null)
{
Logger.Warn("Missing Tool Context Skipping the file");
result.errorType = "Warning";
result.errorMessage = "Missing Tool Context";
result.errorSubject = ErrorCategory.MISSING_TOOL_CONTEXT;
result.success = false;
return result;
}
if (input.SCContext == null)
{
Logger.Warn("Missing Context Skipping the file");
result.errorType = "Warning";
result.errorMessage = "Missing Context";
result.errorSubject = ErrorCategory.MISSING_CONTEXT;
result.success = false;
return result;
}
if (input.WaferContainer == null)
{
Logger.Warn("Missing Wafer Container Skipping the file");
result.errorType = "Warning";
result.errorMessage = "Missing Wafer Container";
result.errorSubject = ErrorCategory.MISSING_WAFER_CONTAINER;
result.success = false;
return result;
}
return result;
}
However the code won't compile. I thought you can assign as many classes as you want to the "T"?
Again both classes have ToolContext, SCContext, and WaferContainer. Instead of writing a function for each, I thought it would be elegant to write one for both. I also have additional inputs in the future to add so I'd like to not need to write this function each time
The why
So when you say this:
public void MyMethod<T>(T value) where T: ClassA, ClassB
You're saying that T should be derived from both ClassA and ClassB. Now it would work in this scenario:
public class ClassA
{
public int SomeProperty { get; set; }
}
public class ClassB : ClassA
{
}
public class ClassC : ClassB
{
}
MyMethod<ClassB>(classBValue); // ClassB is a ClassB and is derived from ClassA
MyMethod<ClassC>(classCValue); // ClassC is derived from ClassB, and is indirectly derived from ClassA
But this won't work:
public class ClassA
{
public int SomeProperty { get; set; }
}
public class ClassB
{
public int SomeProperty { get; set; }
}
Because it requires a ClassC that looks like this:
public class ClassC : ClassA, ClassB
{
}
And this could will cause a compile time error because C# doesn't support multiple inheritance. That is to say that, while you can have a class derived from a class that itself is derived from another class, you can't create a class that directly derives from two classes.
The solution
What you can do is declare an interface:
public interface ISomeInterface
{
int SomeProperty { get; set; }
}
And have both the classes implement it:
public class ClassA : ISomeInterface
{
public int SomeProperty { get; set; }
}
public class ClassB : ISomeInterface
{
public int SomeProperty { get; set; }
}
Then if we change our method signature to require that the class implements our interface:
public void MyMethod<T>(T value) where T: ISomeInterface
Then within the method we can access the SomeProperty property of T:
public void MyMethod<T>(T value) where T: ISomeInterface
{
value.SomeProperty *= 2;
}
Try it online
you need to use an interface
public interface IInput
{
public string ToolContext {get;set;}
public string SCContext {get;set;}
public string WaferContainer {get;set;}
}
public class CIMTDXInput:IInput
{
public string ToolContext {get;set;}
public string SCContext {get;set;}
public string WaferContainer {get;set;}
.... another properties
}
public class RMTTDXInput:IInput
{
public string ToolContext {get;set;}
public string SCContext {get;set;}
public string WaferContainer {get;set;}
.... another properties
}
and your method should be
public static TDX2KlarfResult CheckCIMTDXInput<T>(T input, TDX2KlarfResult result) where T : IInput
or you can get without a generic in this case , would be enough
public static TDX2KlarfResult CheckCIMTDXInput(IInput input, TDX2KlarfResult result)
How would I setup the following classes so that I could have a method that takes a common parent class/interface and allow me to iterate over any child without specifying the generic Type?
public abstract class BaseClass
{ ??? }
public class ChildClass<T> : BaseClass
{
public List<T> SomeList;
???
}
ChildClass<int> childA = new ChildClass<int> ();
ChildClass<string> childB = new ChildClass<string> ();
public void IterateOverChild (BaseClass someChildClass)
{
foreach (var element in someChildClass.SomeList)
{
Console.WriteLine (element);
}
}
Have the abstract class expose some means of accessing the data that is common between the child classes, in this case, a sequence of data where each object can be of any type:
public abstract class BaseClass
{
public abstract IEnumerable Data { get; }
}
public class ChildClass<T> : BaseClass
{
public List<T> SomeList { get; set; }
public override IEnumerable Data { get { return SomeList; } }
}
Use
public abstract class BaseClass<T>
{
public List<T> SomeList { get; set; }
}
public class ChildClass<T> : BaseClass<T>
{
}
public void IterateOverChild<T>(BaseClass<T> someChildClass)
{
foreach (var element in someChildClass.SomeList)
{
Console.WriteLine(element);
}
}
Unless BaseClass knows about <T>, it cannot have any properties or methods of type T. However, you can provide a base implementation that at least exposes a non-generic form of your property. You lose type information but preserve enumerability.
public abstract class BaseClass
{
public IList SomeList { get; set; }
}
public class ChildClass<T> : BaseClass
{
public new List<T> SomeList
{
get { return (List<T>) base.SomeList; }
set { base.SomeList = value; }
}
}
I am attempting to do something similar to:
public interface IView<T> : T where T : class
{
T SomeParam {get;}
}
So that i can later do
public class SomeView : IView<ISomeView>
{
}
Is it possible to specify inheritance using generics in this way or do i have to go the long way round and explicitly specify both interfaces when defining the class and do:
public interface IView<T>
{
T SomeParam {get;}
}
public class SomeView : IView<ISomeView>, ISomeView
{
}
This isn't possible, but your goal may be achievable with conversion operators. It seems that what you're trying to do is make it possible to pass an IView<T> as the T object which it contains. You could write a base class like this:
public abstract class ViewBase<T> {
public abstract T SomeParam { get; }
public static implicit operator T(ViewBase<T> view) {
return view.SomeParam;
}
}
Then, if you define a class like:
public class SomeView : ViewBase<ISomeView> { }
It can be accepted anywhere an ISomeView is expected:
ISomeView view = new SomeView();
Short answer: It is not possible. See this post
An Interface can't derive from a class. However nothing prevent you from doing this:
public interface ISomeView
{
}
public interface IView<out T> where T:class
{
T SomeParam { get; }
}
public class SomeView:IView<ISomeView>
{
public ISomeView SomeParam { get; set; }
}
Edit:
If you don't want to implement the T SomeParam { get; } each time you need to have an implementation, Does this would work?
public interface ISomeView
{
}
public abstract class BaseView<T> where T : class
{
public T SomeParam { get; set; }
}
public class SomeView : BaseView<ISomeView>{
}
In both case this would work:
public class main
{
public class OneOfThoseView : ISomeView
{
}
public main()
{
OneOfThoseView oneOfThose = new OneOfThoseView();
SomeView x = new SomeView();
x.SomeParam = oneOfThose;
}
}
Edit 2:
Not exactly what you want to do but this would force your SomeView class to return a BaseView<SomeView> class
public interface ISomeView
{
}
public abstract class BaseView<T> where T : BaseView<T>
{
public T SomeParam { get; set; }
}
public class SomeView : BaseView<SomeView>
{
}
Now only this would work.
public main()
{
SomeView y= new SomeView ();
SomeView x = new SomeView();
x.SomeParam = y;
}
Ok, so C# has properties
public int Prop {get;set;}
I can put the getter and the setter on separate interfaces like this:
public interface IRead
{ int AnInt { get; } }
public interface IWrite
{ int AnInt { set; } }
And then mix and match them like so:
public class WorkingClass : IRead, IWrite
{
public int AnInt { get; set; }
}
Where it starts to go wrong is where I might have a base object.
public class BaseClass : IRead
{
private int _anInt;
public BaseClass(int anInt)
{ _anInt = anInt; }
public virtual int AnInt
{ get { return _anInt; } }
}
I then want a derived class which can write as well.
public class Derived : BaseClass, IWrite //bits elided
{
public override int AnInt
{
get { return base.AnInt; }
set { throw new NotImplementedException(); } //<-- error
}
}
Which of course doesn't work.
This actually doesn't come up that often. I prefer to have methods with change state and have properties read only. This is design 101 I guess, but as a contrived example, I'd have an Age property with just a get and then a method called IncreaseAge.
So with that all in mind. If you did want to have a mutable object with seperate read and write interfaces how would you do it?
I could do it in a Java-esque way with separate getter/setter methods on each interface. But that negates the benefits of properties + one of the cop programs will yell at me.
You can have the base setter protected and have the derived class implement IWrite explicitly delegating to the base setter:
public class BaseClass : IRead {
public BaseClass(int anInt) { AnInt = anInt; }
public int AnInt {
get; protected set;
}
}
public class Derived : BaseClass, IWrite {
public Derived(int anInt) : base(anInt) { }
int IWrite.AnInt {
set { base.AnInt = value; }
}
}
(The keyword base can even be omitted and the base property doesn't need to be virtual.)