Given this code:
public interface ITagModel { }
public interface ITemplate {
ITagModel Model { get; set; }
}
public class EmailTag : ITagModel { }
public class EmailTest : ITemplate {
public EmailTag Model { get; set; }
}
I am being told that the Type of EmailTag (inside EmailClass) cannot implement the Property Model because it is not the type ITagModel.
It is inheriting ITagModel....so why won't this work? What can I do to accomplish what I'm looking for?
C# doesn't support covariant return.
e.g.
public class Base { }
public class Derived : Base { }
public class Component
{
public virtual Base GetComponent()
{
return new Base();
}
}
public class DerviedComponent : Component
{
public override Dervied GetComponent()
{
return new Derived();
}
}
So you'll need to abstract the return type and constrain it to your interface. That way any implementation will need to supply an ITagModel.
public interface ITagModel { }
public interface ITemplate<TModel>
where TModel : ITagModel
{
TModel Model { get; set; }
}
public class EmailTag : ITagModel { }
public class EmailTest : ITemplate<EmailTag> {
public EmailTag Model { get; set; }
}
It sounds like your ITemplate interface should be generic:
public interface ITemplate<TModel> where TModel : ITagModel
{
TModel Model { get; set; }
}
Then:
public class EmailTest : ITemplate<EmailTag>
{
public EmailTag Model { get; set; }
}
Imagine if your current code worked. I could then write:
ITemplate template = new EmailTest();
template.Model = new SomeOtherModel();
... and you wouldn't want that. (Basically, you'd be violating type safety.)
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'm currently trying to assign an ObservableCollection of an object (in the example below: ObservableCollection<A>), to a field in a parent class that is an ObservableCollection of an interface implemented by the object (in the example below: public ObservableCollection<IOrderable> childModels, where type A implements IOrderable).
This can be seen in the following:
public class A : IOrderable { }
public class B : IOrderable { }
public class Term
{
public ObservableCollection<A> aCollection { get; set; }
}
public class Year
{
public ObservableCollection<B> bCollection { get; set; }
}
public abstract class InfoListViewModelBase : ViewModelBase
{
public ObservableCollection<IOrderable> childModels { get; set; }
}
public class TermViewModel : InfoListViewModelBase
{
public TermViewModel(Term t)
{
this.childModels = t.aCollection;
}
}
public class YearViewModel : InfoListViewModelBase
{
public TermViewModel(Year y)
{
this.childModels = y.bCollection;
}
}
The issue is that this.childModels = t.aCollection; and this.childModels = y.bCollection; both do not work, instead giving the error "Cannot implicitly convert type ObservableCollection<A> to ObservableCollection<IOrderable>" and "Cannot implicitly convert type ObservableCollection<B> to ObservableCollection<IOrderable>"
Is there a correct way of achieving this desired result between the classes?
You could make your InfoListViewModelBase generic.
public abstract class InfoListViewModelBase<T> : ViewModelBase where T:IOrderable
{
public ObservableCollection<T> childModels { get; set; }
}
Your implementations become
public class TermViewModel : InfoListViewModelBase<A> { }
public class YearViewModel : InfoListViewModelBase<B> { }
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.
Short version:
How can I best avoid using multiple type parameters? According to this it is a bad idea.
Long version:
I have 3 interfaces. I have multiple classes implementing these interfaces. It looks something like this:
public interface IMyInterface1 { }
public interface IMyInterface2 { }
public interface IMyInterface3 { }
public class MyClass1A : IMyInterface1 { public int Id { get; set; } }
public class MyClass1B : IMyInterface1 { }
public class MyClass1C : IMyInterface1 { }
public class MyClass2A : IMyInterface2 { }
public class MyClass2B : IMyInterface2 { }
public class MyClass2C : IMyInterface2 { }
public class MyClass3A : IMyInterface3 { }
public class MyClass3B : IMyInterface3 { }
public class MyClass3C : IMyInterface3 { }
Originally I had a base class and a class that derives from it with multiple type parameters like this:
public abstract class MyBaseClass<T, U, V>
where T : IMyInterface1
where U : IMyInterface2
where V : IMyInterface3
{
public T ConcreteMyInterface1 { get; set; }
public U ConcreteMyInterface2 { get; set; }
public V ConcreteMyInterface3 { get; set; }
public abstract T DoStuffWithInterface1();
}
public class MyClass : MyBaseClass<MyClass1A, MyClass2A, MyClass3A>
{
public override MyClass1A DoStuffWithInterface1()
{
var id = ConcreteMyInterface1.Id;
return ConcreteMyInterface1;
}
}
In an effort to remove the type parameters I refactored the code but it resulted in me having to cast everywhere like this:
public abstract class MyBaseClass
{
public IMyInterface1 ConcreteMyInterface1 { get; set; }
public IMyInterface2 ConcreteMyInterface2 { get; set; }
public IMyInterface3 ConcreteMyInterface3 { get; set; }
public abstract IMyInterface1 DoStuffWithInterface1();
}
public class MyClass : MyBaseClass
{
public MyClass()
{
ConcreteMyInterface1 = new MyClass1A();
ConcreteMyInterface2 = new MyClass2A();
ConcreteMyInterface3 = new MyClass3A();
}
public override IMyInterface1 DoStuffWithInterface1()
{
var id = ((MyClass1A)ConcreteMyInterface1).Id;
return ConcreteMyInterface1;
}
}
I was hoping for something more helpful than what Microsoft had to say in the above linked article:
To fix a violation of this rule, change the design to use no more than two type parameters.
I have a abstract base class that implements properties from an interface:
public abstract class AbstractItem : IPropertyListOwner
{
public ObservableCollection<IProperty> Properties { get; }
}
My concrete class now also needs to implement concrete properties:
public class ConcreteItem : AbstractItem
{
public ObservableCollection<ConcreteProperty> Properties { get; }
}
How do I achieve that? Right now I see the following approaches:
Simply use a separate property, don't use that from base class
public class ConcreteItem : AbstractItem
{
public ObservableCollection<ConcreteProperty> ConcreteProperties { get; }
}
Return a new filtered ObservableCollection
public class ConcreteItem : AbstractItem
{
public ObservableCollection<ConcreteProperty> ConcreteProperties
{
get { return new ObservableCollection<ConcreteProperty>(base.Properties.OfType<ConcreteProperty>()); }
}
}
What would you do? Any better approaches?
Generics will help you:
interface IPropertyListOwner<T>
where T : IProperty
{
ObservableCollection<T> Properties { get; }
}
abstract class AbstractItem<T> : IPropertyListOwner<T>
where T : IProperty
{
public abstract ObservableCollection<T> Properties { get; }
}
class ConcreteProperty : IProperty { }
class ConcreteItem : AbstractItem<ConcreteProperty>
{
public override ObservableCollection<ConcreteProperty> Properties
{
get
{
// ...
}
}
}
But this will be inconvenient, if you're planning to work somewhere with IPropertyListOwner.
Suppose, you have some code, that should work only with IProperty. For example, let this code display names of properties:
interface IProperty
{
string Name { get; }
}
In the case of generics, you can't write foreach, that will iterate through collection of properties, without knowing T at runtime:
void WritePropertyNames<T>(IPropertyListOwner<T> owner)
{
foreach (var property in owner.Properties)
{
Console.WriteLine(property.Name);
}
}
In other words, to do something with generic IPropertyListOwner<T> you will need code with generics too.
If you'll post use cases, than it will help to post more clear answer.
public abstract class AbstractItem<T> : IPropertyListOwner where T:IProperty
{
public ObservableCollection<T> Properties { get; private set; }
}
public class ConcreteItem : AbstractItem<ConcreteProperty>
{
}