Generic interface type assignment - c#

I would like to have some validators for input for different objects. On of these is User object.
I want to have a generic interface validator for each child class which validates a specific object. The basevalidator is just an abstract class which contains the the abstract method "validate" and some other useful protected methods. But when i try to assign a new UserValidator to a Validator type i get an error. How could i rewrite this?
public interface Validator<T> {...}
public abstract class BaseValidator<T> : Validator<T> {...}
public class UserValidator : BaseValidator<User> {...
Validator v = new UserValidator(); //ERROR

Actually the error message:
Using the generic type 'Validator<T>' requires 1 type arguments
tells you what to do.
You have to specify the generic parameter of the interface:
Validator<User> v = new UserValidator(); //NO ERROR
Much more important is where you want to use v. Because this determines whether User is known at compile time or not. Please post more context code, so I can adjust my answer to your actual situation

Related

c# Generic Type System - Self Reference Generic Type

Hey so I am trying to create a set of Generics and I cant seem to find the proper way to do this.
What I need is better showcased as an example implementation (which doesnt work):
public abstract class State<T,K> : StateMachine<StateType>{
public T Owner { get;set}
public Y Controller { get;set}
public void Setup(T Owner, Y Controller);
}
public abstract class StateMachine<StateType> where StateType : State<T,K>
where K : "MyOwnImplementationType typeof<this>??"// This refers to the "this" concrete type and not a special provided type, it since I cant seem to constraint to be the correct type, and inheritance type does not work
{
StateType[] states; // This needs to be the actual StateType and not the abstract class
public DoStuff(StateType t){
t.Setup(this, GetOwner()); // doesnt matter where Owner Comes from
}
}
public class ImplementationState : State<ImplementationStateMachine, ImplementationController> {
}
public class ImplementationStatemachine : StateMachine<ImplementationState, ImplementationController> {
}
If I replace MyOwnType with StateMachine, then it complains, and correctly, that my concrete implementation cant be mapped to the generic type.
I have been playing around with using interfaces and CoVariance/ ContraVariance but I cant seem to get the correct setup at all.
Is there anyway this is possible ?
Or any workaround how to setup this?
I am open to suggestions on another way to structure this sort of system.
The requirements is that I am able to access the correct types inside each class and not a generic variant.
The where clauses, apply to the items in the Generic declaration. The only way to do what you are trying to do is this:
public abstract class StateMachine<StateType, T, K>
where StateType: State<T,K>
where K: MyOwnType
From the C# Language specification
A class declaration cannot supply type_parameter_constraints_clauses unless it also supplies a type_parameter_list.
There can be at most one where clause for each type parameter, and the where clauses can be listed in any order
Infering from the in any order and for for each type parameter, it's evident that you need to declare the T,K in the class declaration, to apply any constraints on them.

Generic method returning generic type

I am using a restclient that accepts a type, which is later converted to the correct IRestResponse.
IRestResponse<MyClassA> response = client.Execute<MyClassA>();
Since MyClassA can also be MyClassB or MyClassC I thought about making a generic method which could handle this. However without any luck. This is my attempt:
public interface IRestClient{
IRestResponse response = PerformExecuteClient()
private RestResponse<T> PerformExecuteClient<T>() {
return client.Execute<T>();
}
The compiler tells me that client.Execute<T> does not accept abstract types. Which makes sense, but I have no idea how else to make this method. Is it possible what I am trying to achieve here?
Additional information based on some comments. As Brains Mains suggested, the method is not accepting the abstract type here.
public interface IRestClient{
IRestResponse<T> Execute<T>(IRestRequest request) where T : new();
}
The signature is:
IRestResponse<T> Execute<T>(IRestRequest request) where T : new();
The generic constraint of new does not allow abstract classes.
Instead you can:
Have an interface for your classes and have a generic constraint on that.
Change your MyClassA to not being abstract
Remove the constraint
Me personally - I'd say the interface option - but this is opinion based :)
In any case for the PerformExecuteClient<T> it must follow at least the generic constraints of the Execute<T> which it executes.
Did you try this:
private RestResponse<T> PerformExecuteClient<T>() where T : new()
{
return client.Execute<T>();
}
As everyone pointed out here, you have to follow the interface's generic constraint to make this work. If you don't, you do not respect the interface contract by passing an unexpected type.
Also where T : new() means that you can instantiate T like this new T(). But by definition, an abstract class can't be instantiate, that is why you get this error.
This :
where T : new();
Means that T will be created inside of method. But how can you create instance of abstract class ? Hence an error.
The Execute method on the client object could have a where T: [Something] constraint, which your generic method would also need to apply. Look at the source code (if possible) or documentation to see if a where constraint is applied to the generic.

How do you cast a method argument to a generic without defining the generic's type in c#

First of all the following problem is with a Xamarin app I'm writing but I assume this happens because of C# not because of the underlying Java, if it is because of Java then please tell me so I can correct the question title
I wish to create an abstract class that I will use for the basis of all Fragment classes my project will use. So I have defined it like this:
public abstract class CoreFragment<T> : Fragment
The T in the class represents an interface that must be implemented by whichever class this Fragment attaches to, so for example my code is:
private T _parent;
public override void OnAttach(Activity activity){
if (activity is T){
_parent = activity as T;
} else { throw new Exception("Incorrect type of parent")' }
}
So when I create a new fragment that should be attached only to a type that implements the interface iMainInteractions, I create it as :
public class MyNewFragment : CoreFragment<iMainInteractions>
my problem is that the code above:
_parent = activity as T;
does not compile, I even tried:
_parent = (T) activity;
because it sometimes seems to work where as 'as' doesn't and it keeps throwing a compiler error that T is not specified to be of a specific type (I assume it wants me to define something along the lines of where T : something)
if I remove it and use something like :
_parent = (T) Convert.ChangeType(activity, typeof(T));
it will compile, it will enter the true part of the statement when the time comes but when the ChangeType tries to execute, it will throw an exception saying that activity is not implementing IConvertible
so other than creating a blank iInteraction interface as a parent of T, and having all my interaction interfaces follow this one, is there a way to make this work?
thanks in advance for any help you can provide
You are missing the class constraint:
public abstract class CoreFragment<T> : Fragment where T : class
The problem is the as operator works for reference types only, so it could safely produce a null in case the cast would not be valid. With T unconstraint, the compiler can't tell if it will be substituted with a reference or value type, and thus as can't operate on it.
I don't know what's your class hierarchy, but I'd consider introducing a base interface or class you could use as a type constraint. For example, if all Activity-like classes would have to implement a base interface such as IActivityBase:
public abstract class CoreFragment<T> : Fragment where T : IActivityBase
Such interface need not actually contain any members, and could serve just for the purpose of increased type safety when working with your generic classes.

How to initialize an interface that has type aguments of the type of another Interface

ive run into a problem - these is my class structure
public interface IModel{}
public interface IGenericMapper<T> where T : IModel {...}
public class ActualModel:IModel {...}
public class ActualMapper: IGenericMapper<ActualModel> {...}
My actual code to initialse the mapper is:
IGenericMapper<IModel> mapper;
mapper= new ActualMapper();
It does not compile. I get the error
Cannot implicitly convert type 'ActualMapper' to 'IGenericMapper'.
An explicit conversion exists (are you missing a cast?)
When I do cast it using
mapper= new ActualMapper() as IGenericMapper<IModel>;
the mapper does not get initialized properly (it comes back as NULL)
What am I missing - since ActualMapper() implements IGeneric Mapper and its type impliments `IModel' why can it not initialize mapper.
Is there another way to structure this so achieve what I need?
Thank you so much
Note the solution people have proposed gives me other compilation errors as the mapping Interface has the following members
T GetModel(busO bBusinessObject);
busO SetBusObject(T source, busO target);
apparently you cant have the generic type as an input parameter when its declared at "out"
Pretty sure you're moving into the realm of covarience here with the Generic change;
try this:
public interface IModel{}
public interface IGenericMapper< out T> where T : IModel{}
public class ActualModel : IModel{}
public class ActualMapper : IGenericMapper<ActualModel> {}
and then:
IGenericMapper<IModel> blah = new ActualMapper();
with out the 'out T' the best you can do is:
IGenericMapper<ActualModel> blah = new ActualMapper();
This is a rabbit hole, so be careful especially if you ever try to mix the two :)
http://msdn.microsoft.com/en-us/library/ee207183.aspx
[Edit]
If you want to be able to downcast the generic T, then it has to be out and you cannot use it as an input. You can, however, move some of it to real time in your implementation; i.e. to a check to see if you can cast it to a model type.
interface IGenericMapper<out TModel, in TKeyOrIdent>
TModel GetModel(TKeyOrIdent bBusinessObject);
void SetModel(object model, TKeyOrIdent target);
you have to define
IGenericMapper<out T>
to support your scenario, but this applies other limitations.
Simply IGenericMapper<IModel> != IGenericMapper<ActualModel> even if ActualModel : IModel
In most scenarios it makes sense to have a base interface that isn't a generic. See IList<T> for example, it implements IList.
You can then choose on implementation to explicitly implement interface members. See List<T>.GetEnumerator() : IEnumerable
Do not use generics under the assumption that you can eliminate casting everywhere. I've tried it C# simply doesn't have the required features for this.
I would suggest an IGenericMapper interface as base interface for IGenericMapper<T> then do your generic code on IGenericMapper and finally (and at that point you already have the type) cast it back to the specific type.

Error implementing Generic Class with Type Constraints

I have a Generic Base Class that I want to allow one of two types ITest or IBoldface.
My Base Class looks like this:
public abstract class BaseTestingCollections<T> where T : ITest, IBoldface
{
...
}
One of the classes that inherit it looks like this:
public class TestCollection : BaseTestingCollections<ITest>, ITestCollection
{
...
}
When I compile I get this error:
The type DomainLogic.ITest' cannot be used as type parameter 'T' in the generic type or method 'DomainLogic.BaseTestingCollections'. There is no implicit reference conversion from 'DomainLogic.ITest' to 'DomainLogic.IBoldface'.
Such an either/or restriction can't be done (as I'm sure you've noticed, the comma is more like && than ||). You can either make two different abstract classes with different names (one BaseTestingCollectionsTest<T> where T : ITest, the other BaseTestingCollectionsBoldface<T> where T : IBoldface), or remove the static restriction and put the check at runtime. Or make one of ITest or IBoldface extend the other, or extend a common interface, if they share members.
Here's an example of checking at runtime:
public abstract class BaseTestingCollections<T>
{
public BaseTestingCollections()
{
if (!typeof(ITest).IsAssignableFrom(typeof(T)) && !typeof(IBoldface).IsAssignableFrom(typeof(T)))
throw new Exception();
}
}
Well you're not satistfying the constraint you've specified. T has to extend/implement both ITest and IBoldFace.
Your constraint doesn't mean that it has to extend/implement one of the types - it has to do both. A type argument has to satisfy all the type constraints in order to be valid.
See MSDN on generic constraints for more information.
Per your own generic constraint, only those types which implement both ITest and IBoldface are suitable generic arguments for your BaseTestingCollection class.
It's not either-or, how could it be? What happens when you call method Bar from the ITest interface on a T which only implements IBoldFace, which in turn defines no method Bar? What is a compiler to do when faced with such a scenario?
There is no reasonable action to take. Your constraints apply all at the same time to the generic argument.
You can't express an "either-or" constraint like this with C# generics. Use a common base interface of some sort:
interface ITestOrBold {}
interface ITest : ITestOrBold {}
interface IBoldface : ITestOrBold {}
class BaseTestingCollections<T> where T : ITestOrBold {}
Obviously instead of ITestOrBold you should have some sensible abstraction.

Categories

Resources