I would ideally like Foo<T>
to require that any instantiations themselves implement the T
. (Foo<>
is either abstract, or an interface)
Or if it's actually MyFoo : IFoo<ConcreteClass>
then MyFoo : ConcreteClass
Currently I've achieved my underlying goal by having Foo<T>
declare a property of type T, which is generally satisfied by returning the class itself, but I'm curious as to whether I can do it more directly.
EDIT: I've convinced myself this is impossible. For reference the code in question looks like this:
public abstract class BotController<TBot> : BotController, IBotController<TBot>
{
protected BotController(TBot wrappedBot, PlayerRecord player, long timeout) : base(player, timeout)
{
WrappedBot = wrappedBot;
}
protected TBot WrappedBot { get; set; }
public abstract TBot ControlledBot { get; }
private string cachedName;
public override string BotName => (cachedName = (cachedName ?? WrappedBot.Name));
protected T SafelyPerformBotActionWithTimer<T>(Func<TBot, T> botAction, string errorDescriptor)
{
return SafelyPerformBotActionWithTimer(() => botAction(WrappedBot), errorDescriptor);
}
protected void SafelyPerformBotActionWithTimer(Action<TBot> botAction, string errorDescriptor)
{
SafelyPerformBotActionWithTimer(() => botAction(WrappedBot), errorDescriptor);
}
}
public class BattleshipsController : BotController<IBattleshipsBot>, IBattleshipsBot
{
public BattleshipsController(IBattleshipsBot battleshipImplementation, PlayerRecord playerRecord, long timeout = 1000)
: base(battleshipImplementation, playerRecord, timeout) {}
public override IBattleshipsBot ControlledBot => this;
public IEnumerable<IShipPosition> GetShipPositions()
{
//qqMDM validate Ship Positions here?
return SafelyPerformBotActionWithTimer(b => b.GetShipPositions(), "specifying ship positions");
}
public IGridSquare SelectTarget()
{
var target = SafelyPerformBotActionWithTimer(b => b.SelectTarget(), "selecting a target");
if (target.IsOutsideGrid())
{
throw new ShotOffBoardException($"{BotName} has tried to shoot off the board, aiming at square {target.Row}{target.Column}", this);
}
return target;
}
public void HandleShotResult(IGridSquare square, bool wasHit)
{
SafelyPerformBotActionWithTimer(b => b.HandleShotResult(square, wasHit), "handling shot result");
}
public void HandleOpponentsShot(IGridSquare square)
{
SafelyPerformBotActionWithTimer(b => b.HandleOpponentsShot(square), "handling opponent's shot");
}
public string Name => BotName;
}
>` will succeed)?