I have this class
class A
{
public string OnlyOnA { get; private set; }
public virtual void Accept<T>(ITaker<T> ia) where T : A
{
ia.Take((T)this);
}
}
and this interface
interface ITaker<T> where T : A
{
void Take(T a);
}
with this I can subclass A like following
class B : A
{
public string OnlyOnB { get; private set; }
}
and implement the interface
class BTaker : ITaker<B>
{
public void Take(B b)
{
var v = b.OnlyOnB;
}
}
I get the flexibilty in the Taker class to get the correct type of A and subtypes of A.
but I still need to the cast in A where I have to do (T)this;
how can I avoid the cast?
many thanks.
What you are trying to do is unsafe since you can do:
new A().Accept(new BTaker());
To make this safe you could create a new interface to specify the type of T which can be accepted e.g.
interface IAccept<T> where T : A
{
void Accept(ITaker<T> taker);
}
class A : IAccept<A>
{
public string OnlyOnA { get; private set; }
public virtual void Accept(ITaker<A> ia)
{
ia.Take(this);
}
}
Related
Say I have the following classes:
public abstract class A
{
protected abstract ReturnA Foo();
public void UseFoo()
{
var foo = Foo();
if (foo != null)
{
//logic here
}
}
}
public class B : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnB instead.
}
}
public class C : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnC instead.
}
}
public class ReturnA
{
public int Id { get; set; }
public string Address { get; set; }
}
public class ReturnB
{
public string Id { get; set; }
public string PhoneNumber { get; set; }
}
public class ReturnC
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I know that C# does not support derived return types, but this is not what I need either.
Classes B and C are implementation specific and therefore their return types have nothing to do with eachother.
The reason why I would want to handle this, is because the method UseFoo in class A may have some generic checks and other generic logic, that has nothing to do with the returned object itself.
So I want to "outsource" only the code that is implementation specific and not have to instead make UseFoo abstract and have every implementation write the same generic code.
Is there any way to solve this at all?
EDIT: Neither ReturnC nor ReturnB are derived from ReturnA. Updated with examples.
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);
}
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
Based on your description you may want to use Generics. Since you're creating separate implementations you can apply the interface below to achieve a similar result.
public interface IModel<T>
{
void Dosomething(T model);
}
public class ImplementationB : IModel<B>
{
public void Dosomething(B model)
{
Console.WriteLine(model.someID);
}
}
Some sort of Decorator pattern can solve it, postpone your actual implementation to inner classes and insist on separation of concern, please leave a comment if I miss understood your question:
//added to support inner implementation
interface IModelImpl {
void Do();
}
class A: IModelImpl
{
public long id { get; set; }
public string description { get; set; }
public string code { get; set; }
public void Do(){
console.WriteLine(this.description);
}
}
class B: IModelImpl
{
public long someID { get; set; }
public void Do(){
console.WriteLine(this.someID);
}
}
class C: IModelImpl
{
public long anydesign { get; set; }
public void Do(){
...
}
}
Here is your IModel, pretty much the same, considered like an outer implementation:
public interface IModel
{
void Dosomething(IModelImpl model); //put any model as long it implements IModelImpl
}
Your class implementation should now changed to:
public class ImplemenationA: IModel
{
public void Dosomething(IModelImpl model)
{
//Do more specific work to ImplementationA
model.Do();
}
}
Another class implementation:
public class ImplementationB:IModel
{
public void Dosomething(IModelImpl model)
{
//Do more specific work to ImplementationB like validation
model.Do();
}
}
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.