In C#, i have an interface, and there are some class will implement this interface.
i have a generic utility class, which i want to limit so that the utility class can only be declared using types implementing that interface, as show below, how can i do it??
public interface IMyInterface
{}
public class A : IMyInterface {} // can pass into UtilityClass
public interface B : IMyInterface{}
public class C : B {} // can pass into UtilityClass
public class D {} // can Not pass into UtilityClass
public class UtilityClass<T is IMyInterface>
{
// some utility function
}
Thanks.
You're looking for a generic constraint. These are expressed in C# by using the where keyword after the class name.
public class UtilityClass<T> where T:IMyInterface
{
}
public class UtilityClass<T> where T: IMyInterface
{
// some utility function
}
They are called constraints, you can read more here http://msdn.microsoft.com/en-us/library/d5x73970.aspx
use the where clause:
public interface IMyInterface
{}
public class UtilityClass<T> where T : IMyInterface
{
// some utility function
}
You can add restrictions to generic classes like so:
public class UtilityClass<T> where T : IMyInterface
{
// some utility function
}
Related
I need some sort of way to mark base interfaces and identify if a class implemented the base interface or its derived interface. c# doesn't allow having 'abstract interface'. Is there any way to do this in c#?
public interface IBaseFoo
{
void BaseMethod();
}
public interface IFoo : IBaseFoo
{
void FooMethod();
}
public class Base
{
}
public class A : Base, IFoo
{
}
public class B : Base, IBaseFoo
{
}
Now in the following method I need to check if the typeCls is implemented the IFoo or IBaseFoo without explicitly specifying types. I need sort of a way to mark the base interface and identify it in the method. (ie: if c# allowed having abstract interface, I could have check if IsAbstract property of interfaces of typeClas)
public bool IsBaseFooImplemented<T>(T typeCls) where T : Base
{
// Here I need to check if the typeCls is implemented the IFoo or IBaseFoo
}
Because IFoo : IBaseFoo, every class implementing IFoo also implements IBaseFoo. But not the other way around, so you can simply check whether typeCls is IFoo.
Do note that changing behavior based on implemented interfaces generally is a design smell that bypasses the use for interfaces in the first place.
//somewhere define
static List<IBaseFoo> list = new List<IBaseFoo>();
public class A : Base, IFoo
{
public A()
{
YourClass.list.add(this);
}
}
public class B : Base, IBaseFoo
{
public B()
{
YourClass.list.add(this);
}
}
//then you can check if a class is IFoo or not.
public bool IsBaseFooImplemented<T>(T typeCls) where T : Base
{
foreach(var c in list )
{
if(typeof(c) == typeCls) return true;
}
return false;
}
I have not tested the code but it should work.
I have an abstract class like this:
public abstract class BaseClass
{
...
}
and then i have a lot of classes that derive from BaseClass:
public class DerivedOne : BaseClass
{
...
}
I need to implement an Interface that manage the possibility to implement a method that can uses alle the class derived from BaseClass like parameters:
public interface IErrorParser
{
List<string> ParseErrorMessage(BaseClass base);
}
At this point, if i try to implement a class starting from the interface, in this way
public class FirstParser: IErrorParser
{
public List<string> ParseErrorMessage(DerivedOne derived)
{
...
}
}
i receive the error:
FirstParser does not implement interface member
'IErrorParser.ParseErrorMessage(BaseClass)'
at this point i think that i need to use the generics... But i can't understand how...
Make the IErrorParser interface generic like this:
public interface IErrorParser<T> where T:BaseClass
{
List<string> ParseErrorMessage(string defaultMessage, T service);
}
And then you can implement it like this:
public class FirstParser: IErrorParser<DerivedOne>
{
public List<string> ParseErrorMessage(string defaultMessage, DerivedOne rerived)
{
...
}
}
This is because when you implement an interface you must exactly match all interface members (methods and properties) defined in it.
In your case you need to write
public class FirstParser: IErrorParser
{
public List<string> ParseErrorMessage(string defaultMessage, BaseClass service);
{
...
}
}
An interface contains only the signatures of methods, properties, events or indexers. A class or struct that implements the interface must implement the members of the interface that are specified in the interface definition.
More info: https://msdn.microsoft.com/en-us/library/87d83y5b.aspx
You can create interface like
public interface IErrorParser<T> where T : BaseClass
{
List<string> ParseErrorMessage(string defaultMessage, T service);
}
If you define
public interface IErrorParser
{
List<string> ParseErrorMessage(BaseClass base);
}
you can implement it in a class using DerivedClass like this
public class FirstParser: IErrorParser
{
public List<string> ParseErrorMessage(BaseClass baseObj)
{
DerivedClass derived = (baseObj as DerivedClass);
if (derived == null)
{
// handle null value
}
...
}
}
Edit
base is a keyword and you should not use it as the name of an argument.
I have two contracts (one Generic Interface and the other Non-Generic) as follows:
public interface IGenericContract<T> where T : class
{
IQueryable<T> GetAll();
}
public interface INonGenericContract
{
string GetFullName(Guid guid);
}
I have a class implementing both
public class MyClass<T> :
IGenericContract<T> where T : class, INonGenericContract
{
public IQueryable<T> GetAll()
{
...
}
public string GetFullName(Guid guid)
{
...
}
}
Everything is fine until this point when I compile it.
But now when I try using this class I run into this error
"error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'ConsoleApplication1.MyClass'. There is no implicit reference conversion from 'string' to 'ConsoleApplication1.INonGenericContract'."
class Program
{
static void Main(string[] args)
{
MyClass<string> myClass = new MyClass<string>(); //Error
}
}
If I do not implement the Non-generic contract it works fine. What could be wrong here ?
Thanks
In your code INonGenericContract is part of generic constraint, as it placed after where.
public class MyClass<T> :
IGenericContract<T> where T : class, INonGenericContract
You likely want that:
public class MyClass<T> :
IGenericContract<T>, INonGenericContract where T : class
you are very close, what you have to do is implement the non generic interface, not put a constrain.
public class MyClass<T> :
IGenericContract<T>, INonGenericContract where T : class
{
public IQueryable<T> GetAll()
{
return null;
}
public string GetFullName(Guid guid)
{
return null;
}
}
now you can do this
MyClass<string> myClass = new MyClass<string>();
According what you show
public class MyClass<T> : IGenericContract<T> where T : class, INonGenericContract
T must implement INonGenericContract and string doesn't implement it. In short, string is not a valid parameter for class MyClass
If what you're looking for is implementing IGenericContract<T> AND INonGenericContract you should have
public class MyClass<T> : INonGenericContract, IGenericContract<T>
there is no need to have where T : class since IGenericContract<T> already has that constraint.
In one of my pet projects I have found myself using generics quite a lot and I'm wondering if it is possible to use recursive constraints in a generic class.
Let's imagine I have the following interface
public interface IAmSpecial {}
and the classes implementing it can each be handled by its own class
public class SpecialHandler<T> where T: IAmSpecial {}
I would like to define a class that is generic over any SpecialHandler
public class SpecialWrapperHandler<T> where T : SpecialHandler<SpecialT> where SpecialT: IAmSpecial
{
public SpecialWrapperHandler(T t){}
}
which doesn't compile. I can define the SpecialWrapperHandler class with the following signature
public class SpecialWrapperHandler<T> where T : SpecialHandler<IAmSpecial>
{
public SpecialWrapperHandler(T t){}
}
but then I cannot build it since any SpecialHandler implementation will close the generic value on one implementation of IAmSpecial. Also I cannot declare something like
public class SpecialWrapperHandler<SpecialHandler<T>> where T : IAmSpecial
So is it possible to have a C# construct that recurse generic constraints so I can my SpecialWrapperHandler? If so what construct should I use? And if not, why? A quick read of the generics chapter in the doc doesn't yield many answers...
Pass in a second type parameter for the handler. In that way you can type both parameters.
Like so:
public class SpecialWrapperHandler<H, T> where H : SpecialHandler<T> where T : IAmSpecial
{
public SpecialWrapperHandler(T t){}
}
Proof:
public class X : IAmSpecial { }
public class XHandler : SpecialHandler<X> { }
static void Main(string[] args)
{
X x = new X();
SpecialWrapperHandler<XHandler, X> v = new SpecialWrapperHandler<XHandler, X>(x);
}
I've written a class that looks like this:
public class MyClass<T>
{
public void doSomething()
{
T.somethingSpecial;
}
}
This code doesn't compile because the compiler has no idea what T is. I would like to constrain T so that it must inherit a certain class that defines somethingSpecial. Bonus points if you can tell me how to do the same thing by contraining T so that it must implement a certain interface.
public class MyClass<T> where T: IAmSomethingSpecial
It's called Constraints on Type Parameters.
Use the following type parameter constraint in the class declaration:
public class MyClass<T> where T : MyBaseClass
You can read more about type parameter contraints for example here at MSDN.
What you want is a generic constraint:
public class MyClass<T> where T : SomeParentClass
You need a Generic Constraint:
public class MyClass<T> where T : ISomeInterface
{
public void doSomething()
{
instanceOfT.somethingSpecial();
}
}
public interface ISomeInterface
{
void DoSomething();
}
public class MyClass<T> where T : ISomeInterface
{
public void doSomething()
{
T.DoSomething();
}
}
The where keyword allows you to specify constraints on the given generic type. You could swap out the interface for a class.
Read the documentation. Generic Constraint.
class MyClass<T> where T : someinterfaceorbaseclassthatTmustinherit