I know similar questions have been asked, but I didn't find any which was similar enough to what I did.
Let's say I have this:
public interface IData
{
string Data { get; set; }
}
public interface IJob<out T> where T: IData
{
T JobData { get; } // works because no setter
void Run();
}
public class JobAData : IData
{
public string Data { get; set; }
}
public class JobA : IJob<JobAData>
{
public JobAData JobData { get; private set; } // implements IJob's get plus a set
public JobA(JobAData data)
{
JobData = data;
}
public void Run()
{
//can use JobData nicely here
}
}
And, because of the out parameter, this also works:
List<IJob<IData>> jobs = new List<IJob<IData>>();
jobs.Add(new JobA(new JobAData()));
//in another class, extremely simplified (actually running with Quartz)
foreach (var job in jobs)
{
job.Run();
}
While this works fine, it feels like a hack since I have to remember that JobA needs a setter that is not enforced by the interface.
I originally was using a double IJob interface (an IJob and an IJob<T>) but that meant I had to cast from IJob<T> to IJob and I didn't like that.
Is there any cleaner way to do this?
UPDATE
My original suggestion was to create an abstract class that sets the Data in the constructor,
public abstract class JobBase<T> : IJob<T> where T : IData {
public JobBase(T data) {
JobData = data;
}
public T JobData { get; private set; }
public abstract void Run();
}
forcing derived classes to set the JobData property.
public class JobA : JobBase<JobAData> {
public JobA(JobAData data) : base(data) { }
public void Run() {
//can use JobData nicely here
}
}
ORIGINAL ANSWER
Following the abstract base class idea consider a abstract factory method that would force any derived class to provide data, either in the property itself
public abstract class JobBase<T> : IJob<T> where T : IData {
public T JobData { get { return GetData(); } }
public abstract void Run();
public abstract T GetData();
}
or having a private setter and setting it one time in the constructor
public abstract class JobBase<T> : IJob<T> where T : IData {
public JobBase() {
JobData = GetData();
}
public T JobData { get; private set; }
public abstract void Run();
public abstract T GetData();
}
Any derived implementations would be forced to implement the GetData method.
From what I understand, you want to enforce setter definition on inheritance which would have accessibility restriction as well! If you define a setter method, you would still end up making it publicly accessible. And, "double IJob interface (an IJob and an IJob<T>) but that meant I had to cast from IJob<T> to IJob" doesn't sound good to you.
There are not much solutions to this situation but one work around can be restriction using Abstract Classes. What I am suggesting here is something like this:
public interface IData
{
string Data { get; set; }
}
public interface IJob<out T> where T : IData
{
T JobData { get; }
void Run();
}
public class JobAData : IData
{
public string Data { get; set; }
}
public abstract class Abs_JobA : IJob<JobAData>
{
public abstract JobAData JobData { get; protected set; }
public abstract void Run();
}
public class JobA : Abs_JobA
{
public override JobAData JobData
{
get;
protected set;
}
public JobA(JobAData data)
{
this.JobData = data;
}
public override void Run()
{
//can use JobData nicely here
}
}
So now, you do not implement IJob to subsequent classes but, rather you extend Abs_JobA abstract class.
Related
So, I want to create an interface which has a method that can take in any model class.
For example
I have these three property class
class A
{
public long id { get; set; }
public string description { get; set; }
public string code { get; set; }
}
class B
{
public long someID { get; set; }
}
class C
{
public long anydesign { get; set; }
}
class D
{
public long Router { get; set; }
}
I have an interface
public interface IModel
{
void Dosomething(A model); // Now in this example it takes the A model,But I want it to be set, so that that class that implements the interface can put any model as required
}
Now, I have a class that implements the mode
Since the interface only takes the A model, I can pass in the A model in the class during implementation
public class ImplemenationA: IModel
{
public void Dosomething(A model)
{
Console.WriteLine(model.description);
}
}
Say i have another implemenation Class
Now, I am guessing the below one wouldnt work, as the interface signature enforces only to take a Model A and not any other model
public class ImplementationB:IModel
{
public void Dosomething(B model)
{
Console.WriteLine(model.someID);
}
}
I want to the interface method to be invoked by any implementation class and use any model
While it is unjustified what you're attempting to do... to answer the actual question it is possible using generics...
Take the following for guidance (and example)...
class Test : IJobTask
{
public void Start(string val = "")
{
throw new NotImplementedException();
}
}
public interface ITest
{
void MyMethod<T>(T model) where T : IJobTask;
}
public class ConcreteTest : ITest
{
public void MyMethod<T>(T model) where T : IJobTask
{
}
}
public class Main
{
public Main()
{
var ct = new ConcreteTest();
ct.MyMethod(new Test());
}
}
Your MyMethod will need to perform checks and casts now which kind of defeats the purpose, but this does answer the question of "a method accepting any model"
Use interface for your property classes.
public interface IProperty
{
...
}
class A: IProperty
{
...
}
class B: IProperty
{
...
}
class C: IProperty
{
...
}
class D: IProperty
{
...
}
And then you can pass interface as a parameter:
public interface IModel
{
int getModel(IProperty model);
}
I can't use override since the types don't match and I've read I shouldn't use new to hide it, so how would I accomplish this?
SearchBase and ResultBase will work for 80% of my entities but a few will need specific implementations.
This main problem I see is when I do use new it's all typed during compile time and looks good in the debugger but passing this object to System.Web.Mvc.Controller.Json() seems to have a problem serializing it and they come out null.
public class SearchBase<T>
{
public virtual ResultBase result { get; set; }
}
public class SearchImp : SearchBase<SearchImp>
{
public override ResultImp result { get; set; }
}
public class ResultBase
{
}
public class ResultImp : ResultBase
{
}
You could use this instead:
public class SearchBase<T, TResult> where T: ResultBase
{
public TResult result { get; set; }
}
public class SearchImp : SearchBase<SearchImp, ResultImp>
{
public TResult result { get; set; }
}
public class ResultBase
{
}
public class ResultImp : ResultBase
{
}
This way you don't need to override anything (nothing really to override here) and you can keep it type-safe.
I had abstract base class.
public abstract class TurnBasedGameReferee
{
public ITurnBasedGamePlayer CurrentPlayer { get; private set; }
public TurnBasedGameField PlayingField { get; protected set; }
/*snipped*/
}
And I had inheriting class:
public class TicTacToeReferee : TurnBasedGameReferee { /*snipped*/ }
In TicTacToeReferee I supposed to refer to properties like this:
(ITicTacToePlayer)this.CurrentPlayer;
(TicTacToeGameField)this.PlayingField;
I think, what use of explicit conversions here every time isn't correct.
Is there a way to do so in the context of TicTacToeReferee, these CurrentPlayer and PlayingField were ITicTacToePlayer and TicTacToeGameField type without using explicit conversion every time?
You could use Generics.
public abstract class TurnBasedGameReferee<TPlayer, TField>
where TPlayer : ITurnBasedGamePlayer
where TField : TurnBasedGameField
{
public TPlayer CurrentPlayer { get; private set; }
public TField PlayingField { get; protected set; }
/*snipped*/
}
public class TicTacToeReferee : TurnBasedGameReferee<ITicTacToePlayer, TicTacToeGameField>
It assumes, that ITicTacToePlayer inherits from ITurnBasedGamePlayer and TicTacToeGameField from TurnBasedGameField , but i think was what you was meaning.
Based on Maksim Simkin's answer and your comments you could enforce the type safety you want, but at the cost of an extra generic type parameter and added complexity to your solution:
public interface ITurnBasedGame { }
public interface ITurnBasedGamePlayer<TGame> where TGame : ITurnBasedGame { }
public abstract class TurnBasedGameField<TGame> where TGame : ITurnBasedGame { }
public abstract class TurnBasedGameReferee<TGame, TPlayer, TField>
where TGame: ITurnBasedGame
where TPlayer: ITurnBasedGamePlayer<TGame>
where TField: TurnBasedGameField<TGame>
{
public TPlayer CurrentPlayer { get; private set; }
public TField PlayingField { get; protected set; }
}
And now, considering the following types:
public class TicTacToeGame : ITurnBasedGame { }
public class TicTacToePlayer : ITurnBasedGamePlayer<TicTacToeGame> { }
public class TicTacToeGameField : TurnBasedGameField<TicTacToeGame> { }
public class ChessGame : ITurnBasedGame { }
public class ChessPlayer : ITurnBasedGamePlayer<ChessGame> { }
public class ChessGameField : TurnBasedGameField<ChessGame> { }
The following would be a compile time error:
public class TicTacToeReferee: TurnBasedGameReferee<TicTacToeGame, ChessPlayer, ChessGameField> { }
All that said, this is certainly not worth it just to avoid casting the interface to the concrete type of the class. If you don't like all the casts, then you could always implement private helper properties to clean up your code a little:
public class TicTacToeReferee : TurnBasedGameReferee
{
private TicTacToePlayer CurrentTicTacToePlayer => CurrentPlayer as TicTacToePlayer;
private TicTacToeGameField TicTacToePlayingField => PlayingField as TicTacToeGameField;
....
}
And simply use these properties in your inner implementation.
This is what I want my classes to look like, but this code won't compile. How do I make it work?
public interface ISomeInterface
{
string AMember { get; }
}
public abstract class BaseClass
{
public abstract ISomeInterface AObject { get; }
public abstract IEnumerable<ISomeInterface> AMethod();
}
public class DerivedClass<T> : BaseClass where T : ISomeInterface
{
public T AObject { get; private set; }
public IEnumerable<T> AMethod()
{
return null;
}
}
Compiler errors
'Delfin.Accountancy.DerivedClass' does not implement inherited abstract member 'Delfin.Accountancy.BaseClass.AObject.get'
'Delfin.Accountancy.DerivedClass' does not implement inherited abstract member 'Delfin.Accountancy.BaseClass.AMethod()'
Running on c# 5.0.
Notes
I've tried most obvious implementations, but any of them allow me to implement the base class and expose the strongly typed members at once.
I don't want to make the base class generic, because I'll create static methods on the base class, and also create extension methods that might work in every case of derived classes.
I also need the derived class to be generic, because T has more members than ISomeInterface in the real world case.
Thanks!
What you are asking for is called return type covariance and C# does not support this (see this answer for more details). You have to modify your classes in some way but you haven't indicated what is acceptable. Here is a way that does not change the public API, but changes the abstract methods to protected methods.
public interface ISomeInterface
{
string AMember { get; }
}
public abstract class BaseClass
{
public ISomeInterface AObject { get { return GetAObjectImpl(); } }
public IEnumerable<ISomeInterface> AMethod() { return AMethodImpl(); }
protected abstract ISomeInterface GetAObjectImpl();
protected abstract IEnumerable<ISomeInterface> AMethodImpl();
}
public class DerivedClass<T> : BaseClass where T : ISomeInterface
{
public new T AObject { get; private set; }
public new IEnumerable<T> AMethod() { return Enumerable.Empty<T>(); }
protected override ISomeInterface GetAObjectImpl()
{
return AObject;
}
protected override IEnumerable<ISomeInterface> AMethodImpl()
{
return AMethod();
}
}
Not sure what you're trying to achieve here. Your DerivedClass AObject and IEnumerable effectively hide the base class' declarations. What's your reasoning for wanting your derived class' signature take an interface as its generic parameter?
This will compile:
public interface ISomeInterface
{
string AMember { get; }
}
public abstract class BaseClass
{
public abstract ISomeInterface AObject { get; protected set; }
public abstract IEnumerable<ISomeInterface> AMethod();
}
public class DerivedClass<T> : BaseClass where T : ISomeInterface
{
public override ISomeInterface AObject { get; protected set; }
public override IEnumerable<ISomeInterface> AMethod()
{
return null;
}
}
To make it work you can make your base class generic:
public interface ISomeInterface
{
string AMember { get; }
}
public abstract class BaseClass<T> where T : ISomeInterface
{
public abstract T AObject { get; protected set; }
public abstract IEnumerable<T> AMethod();
}
public class DerivedClass<T> : BaseClass<T> where T : ISomeInterface
{
public override T AObject { get; protected set; }
public override IEnumerable<T> AMethod()
{
return null;
}
}
Why not:
public interface ISomeInterface
{
string AMember { get; }
}
public abstract class BaseClass
{
public abstract ISomeInterface AObject { get; protected set; }
public abstract IEnumerable<ISomeInterface> AMethod();
}
public class DerivedClass : BaseClass
{
public override ISomeInterface AObject { get; protected set; }
public override IEnumerable<ISomeInterface> AMethod()
{
return null;
}
}
You can return any type which implements ISomeInterface interface in AObject property and, because IEnumearable<T> is covariant you can return any enumerable of ISomeInteface implemented class.
First I want to say that I am quite new to C# sharp. Is there any way implement a construct like the following? Or is there any other way to archive this?
public interface IClass
{
Dictionary<Enum, ISecondClass> { get; }
}
public abstract class ClassBase : IClass
{
public abstract Dictionary<Enum, ISecondClass> { get; protected set;}
}
public class ConcreteClass : ClassBase
{
public override Dictionary<ConreteEnum, ISecondClass> { get; protected set;}
}
EDIT:
I forgot to say that the concrete instance of the Dictionary needs to implement a custom Enum-comparer that need a concrete enum to get initialized
For all who are interested in the custom enum-comparer, which is needed in this case, take a look at this link: Custom-Enum-Comparer
You can add a generic type argument to the class/interface level
public interface IClass<TEnum>
{
Dictionary<TEnum, ISecondClass> { get; }
}
public abstract class ClassBase<TEnum> : IClass<TEnum>
{
public abstract Dictionary<TEnum, ISecondClass> { get; protected set;}
}
public class ConcreteClass : ClassBase<ConcreteEnum>
{
public override Dictionary<ConcreteEnum, ISecondClass> { get; protected set;}
}