How to specify generic class within where clause of a generic? - c#

I have the following classes and method:
public class MyGenericClass<T>
where T : class
{
}
public class MyClass
{
public TGen MyMethod<TGen>(TGen myGenClass)
where TGen : MyGenericClass<T>
where T : class
{
return myGenClass;
}
}
However, this gives an error because it cannot resolve the symbol T in MyMethod. I would prefer to not have to have MyMethod<TGen, T> since it seems a bit redundant to me. Is this possible?

You have to specify T before you can use it in a definition. There is no way for the compiler to know what T is.
So you should specify T before you use it (at method level as below, or perhaps at class level with MyClass):
public class MyClass
{
public TGen MyMethod<TGen, T>(TGen myGenClass)
where TGen : MyGenericClass<T>
where T : class
{
return myGenClass;
}
}
You can also use a concrete implementation of the generic type in the where clause:
public class MyClass
{
public TGen MyMethod<TGen>(TGen myGenClass)
where TGen : MyGenericClass<DateTime>
{
return myGenClass;
}
}

If you want to be able to use any MyGenericClass implementation for your TGen type, then you will need to create a base class of the MyGenericClass implementation to use (of course, this limits what functionality you will get for your TGen instance.
public class MyGenericClassBase { }
public class MyGenericClass<T> : MyGenericClassBase { }
public class MyClass<TGen>
where TGen: MyGenericClassBase
{
// Stuff
}

Sounds like you're just forgetting to include T in the list of generic types for the method:
public TGen MyMethod<TGen, T>(TGen myGenClass)
where TGen : MyGenericClass<T>
where T : class
{
return myGenClass;
}

Related

How to prevent illegal ICloneable<T> inheritance in C#?

I have an interface :
public interface ICloneable<out T>
where T : ICloneable<T>
{
T Clone();
}
that should receive a type that implement this interface (as shown below).
And I can create a class that implement it :
public class Class : ICloneable<Class>
{
public Class Clone() { return (Class)MemberwiseClone(); }
}
Great !
But anyone can create a class that implement ICloneable<T> "wrong".
Does exist a way to prevent inheritance as shown below ? (2 examples)
public class Other : ICloneable<Class>
{
public Class Clone() { return new Class(); }
}
public class Other : Class, ICloneable<Class>
{
public Class Clone() { return (Other)MemberwiseClone(); }
}
And allow inheritance as shown below ? (any from 2 examples)
public class Other : ICloneable<Other>
{
public Other Clone() { return (Other)MemberwiseClone(); }
}
public class Other : Class, ICloneable<Other>
{
public Other Clone() { return (Other)MemberwiseClone(); }
}
You cannot overload a class, so:
public class Other : Class {}
public class Other : Class, IC<Other> {}
Will never work.
Now, I'm gonna pull a Jon Skeet and show how you could do this, but then discourage you from doing it. You could do something like this:
public class CloneableOther : Class, ICloneable<Other> { }
public class Other : CloneableOther
{
}
public class CloneableFoo : Class, ICloneable<Foo> { }
public class Foo : CloneableFoo
{
}
What this code is doing is effectively removing the generic parameter from the inheritance. Except, Foo can still do this: Foo : CloneableFoo, ICloneable<Other>, and now you'll have to create two classes for every ICloneable instance.
This goes into that why do you need this in the first place? It is a practice to do Foo : IInterface<Foo>, but there's no way to enforce it. Your best bet is to just do copy and paste and just be sure that the class matches.
Maybe another way is to have in the constructor of Class, a check to see if the type of ICloneable is the type of the class, and to throw an exception if it isn't, and that could sort've feel like a compile time error, if it's done earlier enough in the runtime.

Declaring Method with generic type

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

Generic Constructors and Inheritance

I have a generic class with a class constraint on it.
public class MyContainer<T> where T : MyBaseRow
MyBaseRow is an abstract class which I also want to contain a member of some flavour of MyContainer.
public abstract class MyBaseRow
{
public MyContainer<MyBaseRow> ParentContainer;
public MyBaseRow(MyContainer<MyBaseRow> parentContainer)
{
ParentContainer = parentContainer;
}
}
I am having problems with the constructors of classes inherited from MyBaseRow eg.
public class MyInheritedRowA : MyBaseRow
{
public MyInheritedRowA(MyContainer<MyInheritedRowA> parentContainer)
: base(parentContainer)
{ }
}
Won't allow MyInheritedRowA in the constructor, the compiler only expects and only allows MyBaseRow. I thought the generic class constraint allowed for inheritance? What am I doing wrong here and is there any way I can redesign these classes to get around this?
Many thanks in advance for any responses.
Basically, you can't use generics that way, because the covariance system doesn't work that way with classes. See here: http://geekswithblogs.net/abhijeetp/archive/2010/01/10/covariance-and-contravariance-in-c-4.0.aspx
You can however use an interface like this:
public interface MyContainer<out T> where T : MyBaseRow {
}
And that code will compile.
You can make a covariant generic interface (C#4.0):
public interface IContainer<out T> where T : MyBaseRow
{
}
public class MyContainer<T> : IContainer<T> where T : MyBaseRow
{
}
public abstract class MyBaseRow
{
public IContainer<MyBaseRow> ParentContainer;
public MyBaseRow(IContainer<MyBaseRow> parentContainer)
{
ParentContainer = parentContainer;
}
}
public class MyInheritedRowA : MyBaseRow
{
public MyInheritedRowA(IContainer<MyInheritedRowA> parentContainer)
: base(parentContainer)
{ }
}

C# cross referencing generic classes

I want two generic classes to be able to reference each other. I can't seem to get anything to compile. Tried this:
class Program
{
static void Main(string[] args)
{
}
public class ClassA<BT> where BT: ClassB<ClassA<BT>>
{
BT btvar;
}
public class ClassB<AT> where AT: ClassA<ClassB<AT>>
{
AT atvar;
}
}
This has a practical implementation, but I wanted to avoid a complicated explanation of my own code. I can create closed classes that obey the rule, I just can't seem to describe a generic class or interface for those closed instances.
As fas as I understand, this is impossible, and this is why:
You want A, with a template value of type B.
You want B, with a template value of type A.
If you create a new instance of A, the compiler has to check of T is of type B. To check if it's type B, it has to check if B is of type A, A of type B, etc etc.
You end up creating an endless loop.
The way I ended up doing it was by adding the class as one of its own type parameters. It's not too pretty, but it works.
public abstract class Saver<TSaver, TData>
where TSaver : Saver<TSaver, TData>
where TData : ISaveable<TData, TSaver>
{ ... }
public interface ISaveable<TData, TSaver>
where TData : ISaveable<TData, TSaver>
where TSaver : Saver<TSaver, TData>
{ ... }
public class WorkspaceWindow : ScalingWindow, ISaveable<WorkspaceWindow, WorkspaceWindowSaver>
{ ... }
public class WorkspaceWindowSaver : Saver<WorkspaceWindowSaver, WorkspaceWindow>
{ ... }
This is possible, the following is based on the answer to this question.
public class ClassA<BT, AT> :
where BT : ClassB<AT, BT>
where AT : ClassA<BT, AT>
{
BT btvar;
}
public class ClassB<AT, BT> :
where BT : ClassB<AT, BT>
where AT : ClassA<BT, AT>
{
AT atvar;
}
You won't be able to use the classes directly, you'll need to override them.
public ClassAImp : ClassA<ClassBImp, ClassAImp>
public ClassBImp : ClassB<ClassAImp, ClassBImp>
So you may as well make ClassA and ClassB abstract.
this will compile, but I would like to see you instantiate either ClassA or ClassB:
public class ClassA<TBt> where TBt : ClassB<TBt>
{
TBt _btvar;
}
public class ClassB<TAt> : ClassA<TAt> where TAt : ClassB<TAt>
{
TAt _atvar;
}
"Why would you want to?" sounds like a good question to me. The point of Generics it to allow you to abstract a class to allow it to use multiple types. If the constraint limits the type to a concrete type, you are only allowing the type and its subclasses. If you aren't doing this for subclasses, don't use generics. If you are, how about using an interface?
public interface IClassA<ITB> { }
public interface IClassB<ITA> { }
public class ClassA<AT,BT> : IClassA<BT> where BT : IClassB<AT>
{
BT btvar;
}
public class ClassB<BT,AT> : IClassB<AT> where AT : IClassA<BT>
{
AT atvar;
}
public class ClassADerivedClosed : ClassA<ClassADerivedClosed, ClassBDerivedClosed> { }
public class ClassBDerivedClosed : ClassB<ClassBDerivedClosed, ClassADerivedClosed> { }

Overriding a method returning a generic class

in my Silverlight 4 application I started creating and using some generics and now I stumbled upon the following problem:
In a non-generic class, I have a abstract method, that returns a generic class:
public abstract class DTO_Base()
{
public abstract ServiceModelBase<ServiceNodeBase> CreateBusinessObject();
}
The generic class is defined in the following way:
public abstract class ServiceModelBase<RootNodeType> where RootNodeType : ServiceNodeBase
Naturally, from DTO_Base derived classes will have to override the CreateBusinessObject method:
public class DTO_Editor : DTO_Base
{
public override ServiceModelBase<ServiceNodeBase> CreateBusinessObject()
{
// the object to return have to be of type ServiceModelEditor
// which is derived from ServiceModelBase<ServiceNodeEditor>
// public class ServiceModelEditor : ServiceModelBase<ServiceNodeEditor>
// ServiceNodeEditor is derived from ServiceNodeBase
// public class ServiceNodeEditor : ServiceNodeBase
ServiceModelEditor target = new ServiceModelEditor()
...
Functions to populate the 'target'
...
return target;
}
}
The line return target; causes an error, stating that it isn't possible to implicitly convert the type ServiceModelEditor in ServiceModelBase<ServiceNodeBase>. Also, an explicit conversion via target as ServiceModelBase<ServiceNodeBase> doesn't work.
How would I have to implement this method to work?
Try this:
public interface IDTO<Node> where Node : ServiceNodeBase
{
ServiceModelBase<Node> CreateBusinessObject();
}
public abstract class DTO_Base<Model,Node> : IDTO<Node>
where Model : ServiceModelBase<Node>
where Node : ServiceNodeBase
{
public abstract Model CreateBusinessObject();
#region IDTO<Node> Members
ServiceModelBase<Node> IDTO<Node>.CreateBusinessObject()
{
return CreateBusinessObject();
}
#endregion
}
public class DTO_Editor : DTO_Base<ServiceModelEditor, ServiceNodeEditor>
{
public override ServiceModelEditor CreateBusinessObject()
{
// the object to return have to be of type ServiceModelEditor
// which is derived from ServiceModelBase<ServiceNodeEditor>
// public class ServiceModelEditor : ServiceModelBase<ServiceNodeEditor>
// ServiceNodeEditor is derived from ServiceNodeBase
// public class ServiceNodeEditor : ServiceNodeBase
ServiceModelEditor target = new ServiceModelEditor();
return target;
}
}
I have faced a similar problem before and the only thing reasonable to do is to make the core base class generic also. You can remove the Model generic parameter (and the interface) and it will look a little less scary, but you loose visibility on the functionality of ServiceModelEditor outside of the method.
As it is, you've got to return a ServiceModelBase<ServiceNodeBase>. One option is to make your base class generic:
public abstract class DtoBase<T> where T : RootNodeType
{
public abstract ServiceModelBase<T> CreateBusinessObject();
}
Then:
public class DtoEditor : DtoBase<ServiceNodeBase>
{
public override ServiceModelBase<ServiceNodeBase> CreateBusinessObject()
{
...
}
}
If you are using .Net 4.0 I suggest you use interfaces to define your ServiceModelBase and specify an out variance modifier on that interface generic type:
class ServiceNodeBase { }
class ServiceNodeEditor : ServiceNodeBase {/*implementation*/}
//
interface IServiceModelBase<out RootNodeType>
where RootNodeType : ServiceNodeBase {
}
class ServiceModelEditor : IServiceModelBase<ServiceNodeEditor> {
/*implementation*/
}
//
abstract class DTO_Base {
public abstract IServiceModelBase<ServiceNodeBase> CreateBusinessObject();
}
class DTO_Editor : DTO_Base {
public override IServiceModelBase<ServiceNodeBase> CreateBusinessObject() {
return new ServiceModelEditor();
}
}

Categories