A noob question...
I've got two classes, a common(parent) one and a specialized(child)one :
public abstract class BaseTest
{
public BaseTestSettings Settings{get;set;}
public abstract void Run();
}
public class BaseTestSettings
{
public double SettingsProp1{get;set;}
public double SettingsProp1{get;set;}
}
public class SpecializaedTestSettings : BaseTestSettings
{
public double SpecializaedTestSettingsPropA{get;set;}
public double SpecializaedTestSettingsPropB{get;set;}
}
public class SpecializaedTest : BaseTest
{
public SpecializaedTest()
{
this.Settings = new SpecializaedTestSettings();
}
public override void Run()
{
SpecializaedTestSettings settings = (SpecializaedTestSettings)this.Settings;
}
}
Is there a way to avoid casting in the overridden Run method in the specialized test ? I guess a solution would be to define a Settings property of type SpecializedTestSettings in the SpecializedTest class, but my goal is to avoid to this and declare those properties only once. I guess I can't ?
Use Generics :
public abstract class BaseTest<TSettings> where TSettings : BaseTestSettings
{
public TSettings Settings{get;set;}
public abstract void Run();
}
public class BaseTestSettings
{
public double SettingsProp1{get;set;}
public double SettingsProp1{get;set;}
}
public class SpecializaedTestSettings : BaseTestSettings
{
public double SpecializaedTestSettingsPropA{get;set;}
public double SpecializaedTestSettingsPropB{get;set;}
}
public class SpecializaedTest : BaseTest<SpecializaedTestSettings>
{
public SpecializaedTest()
{
this.Settings = new SpecializaedTestSettings();
}
public override void Run()
{
SpecializaedTestSettings settings = this.Settings;
}
}
If you need a non generic/covariant version you can write a covariant interface or a non generic base type.
Related
I've been reading a lot about composition and trying to figure how I can refactor my inheritance tree using composition. Currently my class looks like this:
public abstract class BaseClass
{
public abstract string displayText { get; }
public abstract List<Parameter> parameters { get; }
public abstract void FireEvent();
}
public abstract class SubClass<T> : BaseClass
{
private string _displayText;
public override string displayText { get { return _displayText; } }
private List<Parameter> _parameters;
public override List<Parameter> parameters { get { return _parameters; } }
private T _value; // ADDED TO SUBCLASS
public abstract Event<T> Evt { get; } // ADDED TO SUBCLASS
public override void FireEvent()
{
Evt.Raise(_value);
}
}
public class IntClass : SubClass<int>{}
public class StringClass : SubClass<string>{} // more subclasses like this
From my understanding, there is both inheritance and composition going on here.
SubClass Has-A: (Composition)
List of Parameters
Field for Event
Behaviour of Event<T> which is called within it's own FireEvent method
SubClass Is-A: BaseClass (Inheritance)
IntClass/StringClass Is-A: SubClass & BaseClass
The reason for creating BaseClass is because I need polymorphic lists. This way I can create a List<BaseClass> and call FireEvent() on each element in the list and access the displayText and List<Parameter> in a loop.
In the future I will need a sub class which doesn't have an Event and a subclass which will accept a parameter in FireEvent(). Other variants might crop up.
How would I replace my current structure entirely with a composition based approach? Is it even doable?
In this example, you have 3 behaviors. Int uses 3, String uses only 2. If you put the code like this, when you change AnotherServiceB, you don't need to be worry about it break String (since String doesn't have that service)
public class FireEventService<T>
{
private T _value; // ADDED TO SUBCLASS
public abstract Event<T> Evt { get; } // ADDED TO SUBCLASS
public override void FireEvent()
{
Evt.Raise(_value);
}
}
public class AnotherService
{
}
public class AnotherServiceB
{
}
public abstract class SubClass<T> : BaseClass
{
private readonly FireEventService<T> _fireEventService;
private readonly AnotherService _anotherService;
private string _displayText;
public override string displayText { get { return _displayText; } }
private List<Parameter> _parameters;
public override List<Parameter> parameters { get { return _parameters; } }
public SubClass(FireEventService<T> fireEventService, AnotherService anotherService)
{
// All those services should use with interface and Dependency Injection
_fireEventService = fireEventService;
_anotherService = anotherService;
}
public void FireEvent() => _fireEventService.FireEvent();
}
public class IntClass : SubClass<int>
{
private readonly AnotherServiceB _anotherServiceB;
public IntClass(FireEventService<int> fireEventService, AnotherService anotherService, AnotherServiceB anotherServiceB)
: base(fireEventService, anotherService)
{ }
public void DoSomethingUsingServiceB()
{
//_anotherServiceB.DoSomething();
}
}
public class StringClass : SubClass<string>
{
public StringClass(FireEventService<string> fireEventService, AnotherService anotherService)
: base(fireEventService, anotherService)
{ }
}
I am calling the base constructor but somehow I need to point to the child one back. Take a look at the example bellow:
//Child
public CompanyEventsView(IAggregator aggregator, IRepository<CompanyEvents> repository, int i)
: base(aggregator, repository, i)
{
}
//Base
public BaseViewModelFor(IAggregator aggregator, IRepository<TSource> repository, int i)
{
Aggregator = aggregator;
var source = repository.GetKey(i);
this.MapFromSourceObject(source); // So "This" here should be pointing to the child class
}
Is there any way of doing this?
this and base do not refer to different instances, they are the same.
If your MapFromSourceObject method is defined in the child class, you can cast this to the child type like: (this as CompanyEventsView).MapFromSourceObject(source).
But this would defeat the whole point of inheritance.
Maybe define MapFromSourceObject as abstract or virtual in the base class?
If your base class depends the implementations of child classes, making the class itself abstract would be a better idea.
Maybe this example helps you a little bit with inheritance:
namespace CSharpConsoleApplication.Tests
{
using System;
using System.Collections.Generic;
using System.Linq;
class TemporaryTest
{
public static void Run()
{
Mother<FirstCompanyEvent> firstChild = new FirstChild(new FirstCompanyEvent("this is wrong"));
firstChild.Print();
Mother<SecondCompanyEvent> intChild = new SecondChild(new SecondCompanyEvent("you are too young to do this"));
intChild.Print();
}
}
public abstract class BaseCompanyEvent
{
protected string Value { get; private set; }
public BaseCompanyEvent(string value)
{
Value = value;
}
public abstract string GetMessage();
}
public class FirstCompanyEvent : BaseCompanyEvent
{
public FirstCompanyEvent(string value)
: base(value)
{ }
public override string GetMessage()
{
return "First born: " + Value;
}
}
public class SecondCompanyEvent : BaseCompanyEvent
{
public SecondCompanyEvent(string value)
: base(value)
{ }
public override string GetMessage()
{
return "Younger brother: " + Value;
}
}
public abstract class Mother<T> where T : BaseCompanyEvent
{
protected T CustomEvent { get; private set; }
public Mother(T customEvent)
{
CustomEvent = customEvent;
}
public abstract void Print();
}
public class FirstChild : Mother<FirstCompanyEvent>
{
public FirstChild(FirstCompanyEvent e)
: base(e)
{ }
public override void Print()
{
Console.WriteLine(CustomEvent.GetMessage());
}
}
public class SecondChild : Mother<SecondCompanyEvent>
{
public SecondChild(SecondCompanyEvent e)
: base(e)
{ }
public override void Print()
{
Console.WriteLine(CustomEvent.GetMessage());
}
}
}
I'm trying to create instance of class Bar but I'm receiving an error:
"Cannot implicitly convert type ConsoleApplication1.Bar to
ConsoleApplication1.BaseFoo<ConsoleApplication1.baseOutput,
ConsoleApplication1.baseInput>"
Any idea what I'm missing or what I'm doing wrong? Any advice will be nice.
public class baseOutput
{
public string output;
}
public class baseInput
{
public string input;
}
public class ExtendOutput : baseOutput
{
public long id;
}
public class ExtendInput : baseInput
{
public long id;
}
public class BaseFoo<baseOutput, baseInput>
{
protected virtual void DoSmth()
{
}
}
public class Bar : BaseFoo<ExtendOutput, ExtendInput>
{
protected override void DoSmth()
{
base.DoSmth();
}
}
public class Test
{
public void Show()
{
}
private BaseFoo<baseOutput, baseInput> CreateInstance()
{
return new Bar(); // Error right here
}
}
I'll give you an example of why you're prevented from doing that.
Imagine instead, your classes were written like this:
public class BaseFoo<TOutput, TInput>
where TOutput : BaseOutput
{
public TOutput Something { get; set; }
}
public class Bar : BaseFoo<ExtendOutput, ExtendInput>
{
}
public class BaseInput { }
public class BaseOutput { }
public class ExtendOutput : BaseOutput { }
public class SomethingElse : BaseOutput { }
Now, you have this method:
private BaseFoo<BaseOutput, BaseInput> CreateInstance()
{
//At this point, Something will be of type ExtendOutput.
return new Bar();
}
So, we call it like this:
var myBar = CreateInstance();
Now, mybar.Something is of type BaseOutput. That's fine, though, because ExtendOutput : BaseOutput, right? Not quite.
What happens when we do this:
myBar.Something = new SomethingElse();
That's valid, because Something expects a BaseOutput, and SomethingElse is a BaseOutput. However, the object is actually a Bar, which explicitly says it should be an ExtendOutput.
The problem is clearer if we attempt to cast it back:
var myBaseFoo = CreateInstance();
myBaseFoo.Something = new SomethingElse();
Bar myBar = (Bar)myBaseFoo;
myBar.Something; // Here, we're told it's going to be an `ExtendOutput`,
// but we get a `SomethingElse`?
That's clearly wrong. And that's why you're prevented from doing what you're trying to do. You can have this behavior with covariance.
Covariance makes it illegal to pass in a TOutput. So, this line
public TOutput Something { get; set; }
Would be invalid. We would only be allowed to expose the getter:
public TOutput Something { get; }
Which alleviates the above problem
Bar is BaseFoo<ExtendOutput, ExtendInput>, and CreateInstance() requires BaseFoo<baseOutput, baseInput> to be returned, so it can't return Bar which is BaseFoo<ExtendOutput, ExtendInput>.
Regardless ExtendOutput inherits baseOutput, when you inherit a generic class the inheritance is invariant.
Consider using interfaces with in and out generic modifiers:
public class baseOutput
{
public string output;
}
public class baseInput
{
public string input;
}
public class ExtendOutput : baseOutput
{
public long id;
}
public class ExtendInput : baseInput
{
public long id;
}
public interface IBaseFoo<out T1, out T2>
{
public void DoSmth();
}
public class Bar : IBaseFoo<ExtendOutput, ExtendInput>
{
public void DoSmth()
{
}
}
public class Test
{
public void Show()
{
}
private IBaseFoo<baseOutput, baseInput> CreateInstance()
{
return new Bar();
}
}
How do I define a factory whose implementations may accept different numbers of parameters?
public abstract class CarFactory
{
public abstract void countStuff(??); //not sure how to define this
}
I would like the factory to be able to create different objects like:
public class BMW : CarFactory
{
public override void countStuff(param1, param2) {}
}
public class Ford : CarFactory
{
public override void countStuff(param1) {}
}
Not sure if "countStuff" should be a factory responsibility, but you could get something similar this way:
public interface ICountParam {}
public class BmwParam : ICountParam
{
public BmwParam(string a)
{
A = a;
}
public string A { get; set; }
}
public class FordParam : ICountParam
{
public FordParam(string a, string b)
{
A = a;
B = b;
}
public string A { get; set; }
public string B { get; set; }
}
public interface ICarFactory<in T> where T : ICountParam
{
void CountStuff(T param);
}
public class BMW : ICarFactory<BmwParam>
{
public void CountStuff(BmwParam param) { }
}
public class Ford : ICarFactory<FordParam>
{
public void CountStuff(FordParam param) { }
}
Usage:
bmw.CountStuff(new BmwParam("A"));
ford.CountStuff(new FordParam("A", "B"));
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;
}