Receiving Generic Class as Parameter - c#

I'm new at Generic Class. I'm making a game right now. I'll have many enemies, which all inherit from a generic EnemyBase class
public abstract class EnemyBase<TState, TTransition>
{
protected StateMachine<TState, TTransition> m_FSM;
}
So as an example, I would have something like this:
public class EnemySquire : EnemyBase<EnemySquire.State, EnemySquire.StateTransition>
{
public enum State
{
IDLE,
WALK,
ATTACKED,
DEAD,
}
public enum StateTransition
{
FOUND_FREE_GRID,
FINISHED,
FREED,
OUT_OF_LIFE,
ATTACKED,
}
}
So far so good. My problem is to receive EnemyBase class as parameter. I want to receive any kind of EnemyBase regardless of its generics. So:
public class Player
{
public void Attack<TState, TTransition>()
{
EnemyBase<TState,TTransition> enemy = GetComponent<EnemyBase<TState,TTransition>>();
}
}
This will work but Attack method is called inside another method so this other method must implement <TState, TTransition> as well and this other method is called by another one... and go on.
I would like to achieve something like:
public void Attack()
{
EnemyBase enemy = GetComponent<EnemyBase>();
}
or
public void Attack()
{
EnemyBase<,> enemy = GetComponent<EnemyBase<,>>();
}
I don't know if these sintaxes are correct or even if they exists but I just want to know if class is EnemyBase, regardless its generics.
Thanks
edit: added what generic type are used for

You can't have a field with an un-bound generic type like EnemyBase<,>.
You need to define either a non-generic base class for the generic one like EnemyBase<TState, TTransition> : EnemyBase or an interface like EnemyBase<TState, TTransition> : IEnemy.
Then you can have an EnemyBase or IEnemy field.

You need to do something like this:
public interface IEnemy
{
StateMachine m_FSM { get ; }
}
public abstract class EnemyBase<TState, TTransition> : IEnemy
{
protected StateMachine<TState, TTransition> m_FSM;
StateMachine IEnemy.m_FSM => this.m_FSM;
}
public class StateMachine
{
}
public class StateMachine<TState, TTransition> : StateMachine
{
}

Related

Casting to arbitrary version of generic class

I have a class as follows:
public class Impactable<T> : where T : Spawnable<T>
{
protected T spawnable = Spawnable<T>.Instance;
void DoSomethingIndependentOfT(){}
}
The reason I have it implemented like this is because Spawnable is a Lazy extendable Singleton. In Impactable, I have of course methods that utilize spawnable, but also methods that don't that I'd like to access externally by casting.
public sealed class EnemySpawnable : Spawnable<EnemySpawnable>
{
}
public class MyEnemyA : Impactable<EnemySpawnable>
{
}
MyEnemyA enemy = new MyEnemyA();
Impactable x = enemy;
x.DoSomethingIndependentOfT();
Is it possible to achieve a cast like this in C# or will I have to re-engineer my code?
No, its not. The type argument constraint on Impactable (where) prevents it. But the refactoring required is non-breaking and trivial. The solution is to promote the type-independent methods to a base class which does not require specialization, like so:
public class Spawnable<T>
{
public static T Instance;
}
public class Impactable
{
internal void DoSomethingIndependentOfT() { }
}
public class Impactable<T> : Impactable where T : Spawnable<T>
{
protected T spawnable = Spawnable<T>.Instance;
}
public sealed class EnemySpawnable : Spawnable<EnemySpawnable>
{
}
public class MyEnemyA : Impactable<EnemySpawnable>
{
}
public class Program
{
public static void Main()
{
MyEnemyA enemy = new MyEnemyA();
Impactable x = enemy;
x.DoSomethingIndependentOfT();
}
}
Even if what you intended would be possible (or is made possible in future versions of C#), it's still much cleaner to do it this way, because it self-documents the intent (methods that do not use generics, should not reside in a container scoped to a constrained type).

Can I choose which constructor Unity will use?

Is it possible to specify in a Unity Resolve which constructor Unity should use?
The object I am trying to create may look something like this:
public class MyObject
{
[UseWhenSunny]
public MyObject(InputOne one)
{
Console.WriteLine("Chose constructor one");
}
[UseWhenRaining]
public MyObject(InputTwo two)
{
Console.WriteLine("Chose constructor two");
}
}
public class InputOne
{
}
public class InputTwo
{
}
My construction could be something like this:
var container = new UnityContainer();
container.RegisterInstance(new InputTwo());
var myObject = container.Resolve<MyObject>();
I can find the correct ConstructorInfo easily enough, but I have not figured out how to force Unity to use this specific constructor?
It's a strange construct when you use different constructors for states within a game/program. If you want to pass two different class types, you could use inheritance for that. You need a common ancestor because InputOne and InputTwo only shares Object as common ancestor. So you need to specify a new base class. In this base class you write the common functionality/definition.
Here is an example:
public abstract class InputBase
{
public abstract void Show();
}
public class InputOne : InputBase
{
public override void Show()
{
Console.WriteLine("Show one");
}
}
public class InputTwo : InputBase
{
public override void Show()
{
Console.WriteLine("Show two");
}
}
public class MyObject
{
public MyObject(InputBase input)
{
// because InputOne and InputTwo can be casted to their base class
// they both can be passed as InputBase.
// InputBase defines the Show method which their derived ones must
// implement (abstract).
input.Show();
}
}
See Inheritance (C# Programming Guide)

Solving virtual member call in constructor

I have an abstract class:
public abstract class ExampleBase : IExampleBase
{
protected ExampleBase()
{
this.SetupData();
}
protected abstract Dictionary<int, Adress> RelevantData { get; set; }
protected abstract void SetupData();
public void ProcessData()
{
// use RelevantData
}
}
And a derived class:
public class Example : ExampleBase
{
public Example()
{
}
protected override void SetupData()
{
this.RelevantData = new Dictionary<int, Adress>
{ 1, new Adress { ... } },
{ 2, new Adress { ... } }
}
}
In the base class, ReSharper tells me
Virtual member call in constructor
I understand that it's dangerous to call the method because of the execution order.. but how can I resolve this issue?
Context: I want to set up data in each derived class which will then be processed in the base class. I wanted to call the SetupData() method in the base class since it's the same in every derived class.
Derived class:
Set up the data
Base class:
Process the data
You don't. You accept the fact this is dangerous, and (try to) prevent this. This is a design flaw!
You could prevent this for example by moving the call to the highest level class, or make every class responsible for it's own, thus removing the unsafe part of the method call. Then you don't need another class (a base class) to take responsibility for its deriving classes.
If that isn't possible. Make very clear using comments or any other method available that the developer should take this problem into account when updating the code.
Call SetupData in the constructor of Example (and every other derived class) not ExampleBase and make Example a sealed class.
The problem is that SetupData could access something that would be initialized by the Example constructor. But the Example constructor is called only after ExampleBase constructor has finished.
Your base class constructor is called first. If your override method in your subclass depends on anything done in its constructor it won't work. Personally I'd look for a different design, maybe passing the abstract class into the derived class rather than using inheritance.
So a couple lines of code in every derived class
If you need to control the process order then you can do this
public abstract class MyBase
{
public void ProcessData()
{
bool processData = true;
}
public MyBase()
{
bool myBase = true;
}
public MyBase(int pass)
{
bool myBase = true;
}
}
public class Example : MyBase
{
public void GetData() {}
public Example()
: base(1)
{
bool example = true;
GetData();
ProcessData();
}
}

Action delegate parameters do not match using implemented abstract class

I have the following abstract class:
public abstract class BaseClass{
public object contents { get; set; }
public Action<BaseClass> mutator;
public abstract void Initialise();
}
This will be used by several classes, which will override the Initialize method to assign a value to contents, which will in turn be mutated using the mutator delegate at specific points in time.
I have the following static class, with each method intended to be used as a mutator:
public static class Mutators{
public static void VariantA(A inputObj){
// inputObj.contents = something else
}
public static void VariantB(A inputObj) { } // etc. etc.
}
I then have class A, which implements BaseClass. I am trying to assign Mutators.VariantA to the mutator delegate, but i'm not able to.
public class A : BaseClass{
public A(){
mutator = Mutators.VariantA;
}
public override void Initialise(){
/* set the value of contents property here */
}
}
Specifically I get the following error: A method or delegateMutators.VariantA(A)' parameters do not match delegate System.Action<BaseClass>(BaseClass)' parameters (CS0123)
I understand that Mutators.VariantA(A) requires an object of type A, and the Action was declared to accept an input of type BaseClass, however as class A implements BaseClass I thought I would have been able to do this ?
Coming from dynamically typed languages i'm having a tough time getting to grips with working with types in this way :(
Is there any way I can point to a function with an input of the abstract type in this way ? Do I need to look at some other design pattern ?
Thanks
I understand that Mutators.VariantA(A) requires an object of type A, and the Action was declared to accept an input of type BaseClass, however as class A implements BaseClass I thought I would have been able to do this ?
Absolutely not.
An Action<BaseClass> has to be able to accept any BaseClass object. So for example, if your code were valid, I would be able to write:
Action<BaseClass> mutator = Mutators.VariantA;
mutator.Invoke(new B());
(Where B is another class derived from BaseClass.)
The fact that B derives from BaseClass makes it valid for the invocation - but it's not going to help your VariantA method work nicely.
It's not really clear why you have a mutator here - I strongly suspect you should abstract BaseClass from its mutations. I still don't follow what you're trying to achieve, but this design pattern isn't going to help you get there in a type-safe way.
You could write:
public abstract class BaseClass<T> where T : BaseClass<T> {
public object Contents { get; set; }
public Action<T> Mutator { get; set; }
public abstract void Initialise();
}
... then:
public class A : BaseClass<A> {
public A() {
Mutator = Mutators.VariantA;
}
}
... as then you'd be writing something which can mutate "A" values. But in my experience this sort of generic nesting gets really messy, really quickly.
I've used your current example and changed the Method Signature of one of the classes to the following and it works
public abstract class BaseClass
{
public object contents { get; set; }
public Action<BaseClass> mutator;
public abstract void Initialise();
}
public static class Mutators
{
public static void VariantA(BaseClass baseClass)
{
// inputObj.contents = something else
}
public static void VariantB(A inputObj) { } // etc. etc.
}
public class A : BaseClass
{
public A()
{
mutator = Mutators.VariantA;
}
public override void Initialise()
{
/* set the value of contents property here */
}
}

In C#, can I know in the base class what children inherited from me?

I have a base class vehicle and some children classes like car, motorbike etc.. inheriting from vehicle.
In each children class there is a function Go();
now I want to log information on every vehicle when the function Go() fires, and on that log I want to know which kind of vehicle did it.
Example:
public class vehicle
{
public void Go()
{
Log("vehicle X fired");
}
}
public class car : vehicle
{
public void Go() : base()
{
// do something
}
}
How can I know in the function Log that car called me during the base()?
Thanks,
Omri
Calling GetType() from Vehicle.Go() would work - but only if Go() was actually called.
One way of enforcing this is to use the template method pattern:
public abstract class Vehicle
{
public void Go()
{
Log("vehicle {0} fired", GetType().Name);
GoImpl();
}
protected abstract void GoImpl();
}
public class Car : Vehicle
{
protected override void GoImpl()
{
// do something
}
}
this.GetType() will give you the type of the current instance
How about this:
GetType().Name
Jon Skeet's reply certainly gets the job done, but I for one do not really like the implementation. I prefer the following which keeps it - in my opinion - simple.
Anyway, .NET provides support for this functionality already by way of virtual methods.
public class Vehicle {
public virtual void Go() {
Log(this.GetType().Name);
}
}
public class Car : Vehicle {
public override void Go() {
base.Go();
// Do car specific stuff
}
}
public class Bus : Vehicle {
}
This will work wether you are refering to an instance by it's base class or its actual class. It does not force you to change the implementation in base clases and well... all the other object orientated niceness of .NET.
If you have full control over the implementation of the base and derived classes, then this implementation should serve you nicely.

Categories

Resources