I don't know whether I'm approaching this from the right angle or not, but either way I can't find syntax that works.
I want to pass 3 generic types to a method - from there I'll use reflection to create objects when I need them. However the object I'm passing is itself generic.
It sort of sounds like nested generics.
Let's say I create an interface:
public interface IAgent<TRequest, TClient, TResponse>
{
}
I have a class like this that implements IAgent:
public class MyClass : IAgent<?>
Then I want to call a method something like this:
public method MyMethod<T>(T obj) where T : IAgent<?>
{
// do somethings here
}
UPDATE
Here's what I currently do at class level.
public sealed class T3Agent
: AppAgent<T3RequestAdapter, T3WebClient, T3ResponseAdapter>
{
}
public abstract class AppAgent<TRequest, TClient, TResponse>
where TRequest : IAgentRequestAdapter
where TClient : CustomWebClient
where TResponse : IAgentResponseAdapter
{
public AppResponse Submit(IAppForm appForm, ServiceLog log)
{
}
}
public sealed class AppManager
{
public AppResponse Submit()
{
var t3 = new T3Agent();
var t3Result = t3.Submit(Form, Log);
return t3Result;
}
}
In the final method, I instantiate a new class (T3Agent), but this is tightly coupled to T3. I want to be able to instantiate AppAgent once and pass the required generic types through the method rather than the class, so that I can reuse the class.
I think you have 2 options:
if you have to work with generic class T from Agent<T> you have to know the type anyway so you have to put it in your generic declaration (see TypeNeeded() method below)
If it is not necessary, then split up the interface in a not generic and in a generic interface and then let IAgent<T> extend IAgent (IAgent<T>: IAgent). Now you can create a method without to know the type for IAgent<T> (see method DoSomething())
public interface IAgent
{
void Action( );
int Calculate( );
}
public interface IAgent< T > : IAgent
{
void Set( T value );
}
public class MyClass
{
public void DoSomething< T >( T agent ) where T : IAgent
{
//...
}
public void TypeNeeded< T, V >( T agent ) where T : IAgent<V>
{
}
}
If you don't know the types for your generic interface yet, your class or method needs to be generic, too:
public class MyClass<TRequest, TClient, TResponse> : IAgent<TRequest, TClient, TResponse>
{
}
Or for the method:
public void MyMethod<T, TRequest, TClient, TResponse>(T obj) where T : IAgent<TRequest, TClient, TResponse>
{
// do somethings here
}
Related
I was using generic types in C# and I am new to using generic types. So, right now I am stuck with a problem. I have some classes like these:
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T>
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
//What will be the syntax of declaring this method
//The syntax of the following method is wrong and incomplete.
//It's there just to give an idea about whai i want to do.
public void MyMethod<T>()
where T : BaseClass<..what to write..>
{
}
}
My question is what will be the correct syntax of declaring MyMethod if I want to call MyMethod like this:
MyMethod<ChildClass1>();
If I understood correctly, you try to filter "MyMethod" so that T is a class of type "ChildClass ...".
You can add a generic parameter to your function like this:
public void MyMethod<T, U>()
where T : BaseClass<U>
{
}
But then you have to call MyMethod in that way.
MyMethod<ChildClass1, MyModel1>();
So it's quite complicated to use.
Another solution is to create a new "blank" class :
public abstract class Base // mark it as abstract if you don't need to use it in your code
{
}
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T> : Base //The class inherits the new class
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
public void MyMethod<T>()
where T : Base
{
}
}
You've forgotten to mention the return type and adding <T> after the class name. For example, if the return type is void, you could declare the method as:
public void MyMethod<T>()
where T : BaseClass<T>
{
}
This will work (by which I mean it compiles)
public void MyMethod<T>()
where T : BaseClass<MyModel1>
{ }
so does this:
public void MyMethod<T>()
where T : ChildClass1
{ }
Further edit after reading your comment...
You can do this:
public class AnotherClass<TBaseClass, TModel> where TBaseClass : BaseClass<TModel>
{
public void MyMethod(TBaseClass input)
{ }
}
I have a term for this, hopefully non-offensive. I call it The Generic Rabbit Hole of Madness. It's what happens when we try to combine generics and inheritance so that one set of classes can accomplish a broad set of goals that become increasingly confusing, and we solve it by adding more generic parameters and more generic classes.
You reach the bottom of the hole if you
- use <dynamic>
- check to see what the actual type is using GetType(), typeof, or is
- get it to compile but can't remember what it's supposed to do
I have the following interface hierarchy:
public interface IActor { ... }
public interface IHealthUser : IActor { ... }
and a third interface:
public interface IAction { void Perform(IActor caster) }
Why is the following not legal and can I get around it somehow?
public class HealthPotion : IAction
{
public void Perform(IHealthUser caster) { ... }
}
The contract defined by IAction states that you can Perform the action on any IActor. Any IActor. Not only IHealthUser. What your HealthPotion tries to do is only implement a subset of IAction, meaning to perform its task only on a subset of IActors. That's not what the IAction interface states.
If you want a specific IAction to be able to restrict the type of IActor it applies to, you can do it using generic constraints:
public interface IAction<TAppliesTo> where TAppliesTo : IActor
{
void Perform(TAppliesTo appliesTo);
}
public class UniversalAction : IAction<IActor>
{
public void Perform (IActor anyone) {}
}
public class HealthPotion : IAction<IHealthUser>
{
public void Perform (IHealthUser healthUserOnly){}
}
You need to implement the same signature as your interface defines. You are using IActor in the interface but then you are using IHealthUser in the implementation of IAction interface. You should implement the Perform with the IActor parameter. It can be called however with class that implements IHealthUser.
Maybe this is a dumb question. But, I don't get the point what I am missing.
Given the following class-definition
public abstract class AbstractBaseClass
{
public abstract void Create(AnotherAbstractClass param1);
}
Wheras AnotherAbstractClass is defined
public abstract class AnotherAbstractClass
{
}
with a concrete implementation
public class AnotherConcreteImplementation : AnotherAbstractClass
{
}
I want to be able to have the override of the Create method to use a concrete type:
public class ConcreteImplementation : AbstractBaseClass
{
public override void Create(AnotherConcreteImplementation param1) <-- There is no suitable method for override
{
// param1 is an instance of the concrete implementation
}
public override void Create(AnotherAbstractClass param1) <-- this is working but I'll have to cast on each implementation
{
// param1 is an instance of the abstract class and needs a cast
}
}
Is this simply not possible or is there some way I'm not aware of? Maybe using generics?
Edit #1 (added more context)
I'm trying to achieve/enforce that in a concrete implementation there is only one parameter valid.
Think of it like it's a database-layer. The Create method will create a new entry in the database. As of each table has different values, the create-parameter also has.
The casting inside smells (in my opinion) as of it can be called with any concrete implementation of AnotherAbstractClass.
public class AddressTable : AbstractBaseClass
{
public override void Create(AnotherAbstractClass param1)
{
// cast to concrete instance
var casted = (ConcreteAddressCreate)param1;
}
}
public class CityTable : AbstractBaseClass
{
public override void Create(AnotherAbstractClass param1)
{
// cast to concrete instance
var casted = (ConcreteCityCreate)param1;
}
}
Having an instance of AddressTable I can call
addressIntance.Create(new ConcreteAddressCreate()); // would be okay
on the other hand I can call it
addressIntance.Create(new ConcreteCityCreate()); // would be okay but will fail at runtime with InvalidCastException
Edit #2 (additional info)
It should also be possible to extend the AbstractBaseClass class with more abstract methods later.
So, for me it's more likely to have generic methods instead of an concrete class-implemenation with 200 generic parameters for each method to implement.
It violates the Liskov Substitution Principle so it makes perfect sense you can't do this. Namely, you can't just "have" covariance like this for free:
AbstractBaseClass bcl = new ConcreteImplementation();
bcl.Create(new DifferentImplementationWithoutSecondAbstract());
The contract AbstractBaseClass defines makes Create have to work with any implementation of AbstractBaseClass passed in - if you give a constraint on what can be passed in you've violated the contract it defines.
Like you assumed - you can use generics:
// notice the recursive definition, we require the generic parameter
// to be a generic parameter of itself - allowing AbstractBaseClass
// to not be aware of its subclasses like in the other answers.
public abstract class AbstractBaseClass<T> where T : AbstractBaseClass<T>
{
public abstract void Create(T param1);
}
public class Concrete : AbstractBaseClass<Concrete>
{
public override void Create(Concrete param1)
{
Console.WriteLine("Hello!");
}
}
Yes, you can do that using generics:
public abstract class AbstractBaseClass<T>
where T : AnotherAbstractClass
{
public abstract void Create(T param1);
}
public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
public override void Create(AnotherConcreteImplementation param1)
{
}
}
Generics is indeed the way to do it.
public abstract class AbstractBaseClass<TDerivedClass> where TDerivedClass : AnotherAbstractClass
{
public abstract void Create(TDerivedClass param1);
}
And then you can do:
public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
public override void Create(AnotherConcreteImplementation param1) // Works because TDerivedClass = AnotherConcreteImplementation
{
...
}
}
I have the following and at some point I need to create Failures for Validations. We suppose each type deriving from Validation has one and only one type deriving from Failure<T> where T is the aforementioned implementation of Validation.
As I have a growing number of implementations of Validation, I need to be able to instantiate the right type deriving from Failure<T>, and call the link method on it within a method that looks like
void recordFailureForValidation(Validation v) {
Type failureType = dict[v.GetType()];
Object failure = Activator.CreateInstance(failureType);
// how do I call failure.link(v) ?
}
At Runtime, a dictionary gives me the type deriving from Failure<T> given T.
I am able to instantiate Failure<T> (Failure1, Failure2, etc...), but I can't find how to call link on the public field reference of my newly created Failure instance (by making all uses that made sense to me of GetMethod, MakeGenericMethod, Invoke, etc...)
public class MyReferenceClass<T>
where T : Object, new() {
public void link(T arg) { ... }
}
public abstract class Failure<T>
where T : ValidationRule, new() {
...
public MyReferenceClass<T> reference;
...
}
public class Failure1 : Failure<Validation1> {
}
public class Failure2 : Failure<Validation2> {
}
public abstract class ValidationRule {
...
}
public class ValidationRule1 : ValidationRule {
...
}
public class ValidationRule2 : ValidationRule {
...
}
link is private since you do not specify a different accessibility. Make it public or internal:
public class MyReferenceClass<T>
where T : Object, new() {
public void link(T arg) { ... }
}
then you can call it from Failure<T> through the reference property:
public abstract class Failure<T>
where T : ValidationRule, new()
{
protected T Validation {get; set;};
public MyReferenceClass<T> reference;
}
public class Failure1 : Failure<Validation1>
{
public void Test()
{
this.reference.link(Validation);
}
}
Let Failures implement a non generic IFailure interface as well as a generic one in the same manner as IEnumerable and IEnumerable<T>
Create an abstract factory method within ValidationRule that has to be implemented by each concrete Validation
public ValidationRule1 : ValidationRule
{
public override IFailure ToFailure()
{
return new Failure1(this);
}
...
}
I've the following scenario
I've an Interface
public interface ImyInterface
{
void myInterfaceMethod(string param);
}
I've an Abstract Class
public abstract class myAbstractClass
{
public myAbstractClass()
{
//something valid for each inherited class
}
public void myAbstractMethod<T>(T param)
{
//something with T param
}
}
I've a class that inherits from myAbstractClass and implements ImyInterface
public class myClass : myAbstractClass, ImyInterface
{
public myClass():base()
{}
public void ThisMethodWillNeverCall()
{
// nothing to do
}
}
And, finally, I've a class where I'll create a ImyInterface object. At this point I would call myAbstractMethod, but...
public class myFinalClass
{
public void myFinalMethod()
{
ImyInterface myObj = _myContainer<ImyInterface>();
myObj.???
}
}
Obviously there isn't this method because it isn't declared into the interface.
My solution is the following
public interface ImyInterface
{
void myInterfaceMethod(string param);
void myFakeMethod<T>(T param);
}
public class myClass : myAbstractClass, ImyInterface
{
public myClass():base()
{}
public void ThisMethodWillNeverCall()
{
// nothing to do
}
//--- a fake method
public void myFakeMethod<T>(T param)
{
base.myAbstractMethod<T>(param);
}
}
Is there any other solution better than mine?
Thank you!
First of all, your naming convention is a mess. Read up on the guidelines that Microsoft have made.
It's also hard to tell what you are trying to achieve based on your example.
Back to your question:
You should only access an interface to work with that interface. Don't try to make any magic stuff with classes/interfaces to get them working together. That usually means that the class shouldn't try to implement the interface.
It's better that you create a new interface which have the features that you want and let your class implement both.