I have an abstract class like this:
public abstract class ResourceFilter<TFilter> : SomeOtherClass
{
public static readonly ResourceFilter<ActorTypeEnum> ActorType = new ActorTypeResourceFilter();
protected ResourceFilter(string name, string friendlyName)
: base(name, friendlyName)
{
}
public abstract string GetFilterDisplay<T>(T filter);
public abstract string GetFilterValue<T>(T filter);
public virtual string GetComparisonValue<T>(T compare)
{
return Value + "_" + GetFilterValue(compare);
}
public abstract TFilter GetDefaultFilter();
protected TFilter TypeCheck<T>(T value)
{
if (value is null)
throw new ArgumentNullException(nameof(value));
if (value is TFilter excpectedType)
return excpectedType;
throw new FriendlyException($"Type {value.GetType()} is not valid for this Resource Filter");
}
}
Which has a concretion like this:
public sealed class ActorTypeResourceFilter : ResourceFilter<ActorTypeEnum>
{
internal ActorTypeResourceFilter()
: base(nameof(ActorType), "Actor Type")
{
}
public override string GetFilterDisplay<T>(T filter)
{
ActorTypeEnum actorType = TypeCheck(filter);
return actorType.FriendlyName;
}
public override string GetFilterValue<T>(T filter)
{
ActorTypeEnum actorType = TypeCheck(filter);
return actorType.Name;
}
public override ActorTypeEnum GetDefaultFilter()
{
return ActorTypeEnum.User;
}
}
I want to be able to use the abstract class as the type on a class:
public class ClassToApplyResourceFilter
{
public ResourceFilter ResourceFilter {get; private set;}
}
I'm unable to use ResourceFilter as the type without providing TFilter, which defeats the point of making it generic
If you want to have generic type for a field, you have to make generic containing class as well:
public class ClassToApplyResourceFilter<TFilter>
{
public ResourceFilter<TFilter> ResourceFilter { get; private set; }
}
You could use Covariance and Contravariance (C#) to allow more flexible approach, but for that you need to define interface
as base for abstract class, as only interface/delegate generic type parameters can be specified as variant.