To define a generic class:
public class TParent<T1, T2> { }
public class ChildManager<T1, T2, T3> where T3 : TParent<T1 , T2> { }
public class Child : TParent<int , double> { }
The class Child is an avaliable T3 type for ChildManager , but the class definiton of ChildManager is too long.
The T3 is derived from Tparent , and the T1,T2 has been already defined in TParent.
So, can the definiton be like such code?
public class ChildManager<T3> where T3:TParent<classtype,classtype> { }
However,such code is an error.
Related
Below are working classes:
public class CatalogManager<T1, T2, T3> where T1 : CatalogDataEntryForm<DataEntryControl>, new()
where T2 : CatalogDataGridForm<DataGridControl>, new()
where T3 : CatalogBusinessObject
{
public CatalogManager()
{
_DataGridFrom = new T2();
InitGridformToolbarItemeEvents();
}
}
public class BankDataEntryForm : CatalogDataEntryForm<BankDataEntryControl>
{
}
public class BankDataGridForm : CatalogDataGridForm<BankDataGridControl>
{
}
However, below derived class is complaining with error:
public class BankManager : CatalogManager<BankDataEntryForm, BankDataGridForm, BankBo>
{
public BankManager()
{
}
}
Error message:
Error CS0311 The type 'BankDataEntryForm' cannot be used as type
parameter 'T1' in the generic type or method 'CatalogManager'. Error CS0311 The type 'BankDataGridForm' cannot be used as type
parameter 'T2' in the generic type or method 'CatalogManager'
Many thanks for your help.
The issue is a Covariance and Contravariance in Generics as SLaks say DataEntryControl is not the same as BankDataEntryControl, although They are an inheritance relationship.
Starting with the .NET Framework 4, Visual Basic and C# have keywords that enable you to mark the generic type parameters of interfaces and delegates as covariant or contravariant.
so you can try to make the interface for those class.
ICatalogDataEntryForm<out T> for CatalogDataEntryForm<T>
ICatalogDataGridForm<out T> for CatalogDataGridForm<T>
then let those class implement interface
public interface ICatalogDataEntryForm<out T>
{ }
public interface ICatalogDataGridForm<out T>
{ }
public class CatalogDataEntryForm<T> : ICatalogDataEntryForm<T>
{ }
public class CatalogDataGridForm<T> : ICatalogDataGridForm<T>
{}
BankDataGridForm and BankDataEntryForm no need to change.
public class BankDataGridForm : CatalogDataGridForm<BankDataGridControl>
{
}
public class BankDataEntryForm : CatalogDataEntryForm<BankDataEntryControl>
{
}
public class BankManager : CatalogManager<BankDataEntryForm, BankDataGridForm,CatalogBusinessObject>
{
public BankManager()
{
}
}
Then let CatalogManager class contract with those interface
public class CatalogManager<T1, T2, T3> where T1 : ICatalogDataEntryForm<DataEntryControl>, new()
where T2 : ICatalogDataGridForm<DataGridControl>, new()
where T3 : CatalogBusinessObject
{
public CatalogManager()
{
}
}
c# online
i saw some c# asp.net source code written as below:
public class EntityInstanceContext<TEntityType> : EntityInstanceContext
{
/// <summary>
/// Initializes a new instance of the <see cref="EntityInstanceContext{TEntityType}"/> class.
/// </summary>
public EntityInstanceContext()
: base()
{
}
can anyone help me to understand why the generic type is subclassing from non-generic one? and what is benifit of designing in that way?
The .NET TypeSystem is a very powerful one.
Imagine the following scenario. I'm writing a class called MyTuple which is a poorly coded clone of the BCL Tuple class:
public class MyTuple<T1, T2> {
public T1 Item1 { get; private set; }
public T2 Item2 { get; private set; }
public MyTuple(T1 item1, T2 item2) {
this.Item1 = item1;
this.Item2 = item2;
}
}
And then I realize I want to make a factory kind of method for that type
so that I can successfully hook into the type inference system and not specify T1 and T2 when I don't have to like so:
new MyTuple<int, string>(123, "test"); // which is also a bit redundant
So I'm writing the method I was talking about in a class, let's call the class Factory:
public class Factory {
public static MyTuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) {
return new MyTuple<T1, T2>(item1, item2);
}
}
That way, I'm happier when writing:
var tuple = Factory.Create(123, "test"); // and tuple is inferred to be of <int, string>
Now what would happen if I renamed Factory to MyTuple:
public class MyTuple {
public static MyTuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) {
return new MyTuple<T1, T2>(item1, item2);
}
}
In short: nothing bad
It is simply the case that I now have 2 completely distinct types:
MyTuple (nongeneric)
MyTuple < T1, T2 >
They have nothing in common, they are different types.
And am I allowed to say that MyTuple<T1, T2> just happens to extend MyTuple ?
Well, as long as MyTuple is neither static nor sealed, yeah, sure !
public class MyTuple { ... }
public class MyTuple<T1, T2> : MyTuple { ... }
So in your case it's nothing more that Mammal extending Animal or ... Tiger extending Mammal.
It's not like Mammal of a weirder sort extending Mammal of a good ol' classical sort.
Having
public interface IGeneric<T>{}
public class Student{}
public class Teacher{}
this is possible
public class ConcreateClass : IGeneric<Student>, IGeneric<Teacher>{}
this is not possible
public class GenericClass<T1, T2> : IGeneric<T1>, IGeneric<T2> {}
because GenericClass<String, String> instance; would cause ambiguity for the two interface implementation. But why this is not possible
public class GenericClassWithTypeConstraints<T1, T2> : IGeneric<T1>, IGeneric<T2>
where T1 : Student
where T2 : Teacher
{}
as T1 and T2 cannot be of the same class? (The compiler error is the same as in the case without type constrains)
Edit
"Soner Gönül" in Why does this result in CS0695 proposed a workarround, using two levels of class inheritance, like this:
public interface IGeneric<T> { String Name { get; } }
public class Student{}
public class Teacher{}
public class GenericClassBase<T1> : IGeneric<T1>
where T1 : Student
{ String IGeneric<T1>.Name { get { return "Generic class of Student"; } } }
public class GenericClassDerived<T1, T2> : GenericClassBase<T1>, IGeneric<T2>
where T1 : Student
where T2 : Teacher
{ String IGeneric<T2>.Name { get { return "Generic class of Teacher"; } } }
Code like this then produce expected result
GenericClassDerived<Student, Teacher> X = new GenericClassDerived<Student, Teacher>();
Console.WriteLine(((IGeneric<Student>)X).Name); //outputs "Generic class of Student"
Console.WriteLine(((IGeneric<Teacher>)X).Name); //outputs "Generic class of Teacher"
as T1 and T2 cannot be of the same class?
Yes, they can be the same class. Constraints cannot be sealed classes1 so Teacher can be derived from Student or vise versa. It's not logical but compiler has no idea about it.
For example,
using System;
public class Student{}
public class Teacher : Student{}
public class GenericClassWithTypeConstraints<T1, T2>
where T1 : Student
where T2 : Teacher
{}
class Test {
static void Main() {
var obj = new GenericClassWithTypeConstraints<Teacher, Teacher>();
}
}
will compile without any problem. Demo
Docs:
Constraints can also be class types, such as abstract base classes.
However, constraints cannot be value types or sealed classes.
Similiar to this question: How can I require a method argument to implement multiple interfaces?
I want a method argument to implement several interfaces.
The interfaces shall be combinable in arbitrary fashion and I don't want to create an interface for each valid combination.
Think of a file. It can be:
readable => IReadable
writeable => IWriteable
an archive => IArchive
automatically generated => IGenerated
...
If I want to express that an argument needs to be an writable, generated archive I don't want to generate IWritableGeneratedArchive since there are too combinations and I want to use it with some existing classes I cannot modify.
Pseudocode:
void WriteTo( IWritable + IGenerated + IArchive file)
{
//...
}
The solution I found here: How can I require a method argument to implement multiple interfaces? adjusted for C#.
Credits go to Michael Myers
internal interface IF1
{
void M1();
}
internal interface IF2
{
void M2();
}
internal class ClassImplementingIF1IF2 : IF1, IF2
{
public void M1()
{
throw new NotImplementedException();
}
public void M2()
{
throw new NotImplementedException();
}
}
internal static class Test
{
public static void doIT<T>(T t) where T:IF1,IF2
{
t.M1();
t.M2();
}
public static void test()
{
var c = new ClassImplementingIF1IF2();
doIT(c);
}
}
A generic + constraint perhaps?
void WriteTo<T>( T file) where T : IWritable,IGenerated,IArchive
{
//...
}
Use generic constraints:
void WriteTo<T>(T file) where T: IWritable, IGenerated, IArchive
{
//...
}
See Constraints on Type Parameters (C# Programming Guide)
I don't want to generate IWritableGeneratedArchive since there are too combinations
How are there too many combinations? Whatever number of potential combinations there are, you only need to make a combined interface for the ones you actually use as a method parameter, and at that point you're writing it all out anyway. In other words, it's actually not that much more work.
I want to use it with some existing classes I cannot modify.
An IWritableGeneratedArchive type can be passed to something that only wants an IArchive or IWritable. This would still work with anything else you already have.
But since you've already decided against this and it looks like you already invested a lot in this architecture, I wonder if you've seen Code Contracts. They look like they might do what you need.
This solution tries to incorporate supercat's idea with storing such "multi interface" objects.
I've done this by storing them in a Holder class that exposes the stated interfaces of the object.
Holder objects can be stored and are the expected argument. The downside is that you have to create the Holder first and that the order of Holder's type arguments matters.
On the plus side though you can also dynamically create Holders and of course store "multi interface" objects.
It would have been nice to enable the holder.Get<T>() methods (nicer than holder.t1) but it won't compile.
Maybe someone has an idea how to fix it? I think it needs to add the constraint T1 is not T2 and vice versa. This seams to be related to C# generic does *not* implement something and they didn't find a solution.
internal interface IF1
{
void M1();
}
internal interface IF1_extension : IF1
{
}
internal interface IF2
{
void M2();
}
internal class ClassImplementingIF1IF2 : IF1_extension, IF2
{
public void M1()
{
throw new NotImplementedException();
}
public void M2()
{
throw new NotImplementedException();
}
}
internal interface Getter<T> where T : class
{
T Get();
}
internal class Holder<T1, T2> //: Getter<T1>, Getter<T2> // not possible since T1 and T2 may be the same => won't compile!
where T1 : class
where T2 : class
{
private Holder(T1 t1, T2 t2)
{
Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
this.t1 = t1;
this.t2 = t2;
}
public static Holder<T1, T2> CreateFrom<T>(T t) where T : T1, T2
{
return new Holder<T1, T2>(t, t);
}
public static Holder<T1, T2> CreateDynamicallyFrom(object t)
{
return new Holder<T1, T2>(t as T1, t as T2);
}
public readonly T1 t1;
public readonly T2 t2;
//T1 Getter<T1>.Get()
//{
// return t1;
//}
//T2 Getter<T2>.Get()
//{
// return t2;
//}
}
internal class Holder<T1, T2, T3> // Holder<T1,T2,T3,T4> etc. are defined in a similar way
where T1 : class
where T2 : class
where T3 : class
{
private Holder(T1 t1, T2 t2, T3 t3)
{
Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
Debug.Assert(t3 != null, "Argument is no " + typeof(T3).Name);
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
public static Holder<T1, T2,T3> CreateFrom<T>(T t) where T : T1, T2, T3
{
return new Holder<T1, T2, T3>(t, t, t);
}
public static Holder<T1, T2, T3> CreateDynamicallyFrom(object t)
{
return new Holder<T1, T2, T3>(t as T1, t as T2, t as T3);
}
public readonly T1 t1;
public readonly T2 t2;
public readonly T3 t3;
}
internal static class Test
{
public static void doIt<T>(T t) where T : IF1, IF2
{
t.M1();
t.M2();
}
public static void doIt(Holder<IF1, IF2> t) // Interfaces should be mentioned in alpahbetical order since Holder<IF1,IF2> != Holder<IF2,IF1>
{
t.t1.M1();
t.t2.M2();
}
public static void doIt_extended<T1, T2>(Holder<T1, T2> t) // handles conversions from Holder<T1,T2> to Holder<T1 or base of T1, T2 or base of T2>
where T1 : class, IF1
where T2 : class, IF2
{
t.t1.M1();
t.t2.M2();
}
public static void test()
{
var c = new ClassImplementingIF1IF2();
doIt(c);
var c_holder = Holder<IF1, IF2>.CreateFrom(c);
doIt(c_holder);
var another_c_holder = Holder<IF1_extension, IF2>.CreateFrom(c);
doIt_extended(another_c_holder);
object diguised_c = c;
var disguised_c_holder = Holder<IF1, IF2>.CreateDynamicallyFrom(diguised_c);
doIt(disguised_c_holder);
}
}
Should this be possible using c# 4 and VS 2010? I am doing some processing on class(es) which implements generic interface(s), and after processing would like to convert the objects to a simpler interface so I can extract certain properties defined by common Interfaces.
interface IMyInterface
{
public Id { get; set; }
}
interface IFile<T1, T2> where T1 : IMyInterface where T2 : IMyInterface
{
Int64 prop1 { get; set; }
T1 t1 { get; set; }
T2 t2 { get; set; }
}
ClassA : IMyInterface
{
... Implement some properties plus interface
public Id { get; set; }
}
ClassB : IMyInterface
{
... Implement some properties plus interface
public Id { get; set; }
}
For example this class has ClassX and ClassY which I want to be certain types for processing/saving, but after that I only want to extract common properties like an ID which is common amongst all classes that Implement this generic Interface (other properties are not common in t1, t1)
ClassSomething : IFile<ClassA, ClassB>
{
... Implement properties plus interface
public ClassX t1
{ get {} set {} }
public ClassY t2
{ get {} set {} }
}
IList<IFile<TItem1, TItem2>> list = new List<IFile<TItem1, TItem2>>()
ClassA ca = new ClassA();
... Fill in the interface defined properties
... Fill the list with objects of ClassSomething
foreach (IFile<TItem1, TItem2> x in list)
{
// This fails
IFile<IMyInterface, IMyInterface> interfaceItem =
(IFile<IMyInterface, IMyInterface>)x;
}
The cast of x above (t1 and t2 properties specifically) to the simpler IMyInterface interface fails.
There are quite a few generic interface questions but I didn't see (or recognize?) any solutions.
The solution you are looking for is called variance (covariance and contravariance). However your IMyInterface cannot be made either covariant or contravariant in T1 and T2, because it has both public getters and public setters accepting T1 and T2:
interface IAnimal {}
class Dog : IAnimal { public void Bark () ; }
class Cat : IAnimal { public void Meow () ; }
var dogs = new FileImpl<Dog, Dog> () ;
dogs.t1 = new Dog () ;
var file = (IFile<IAnimal, IAnimal>) dogs ; // if this were OK...
file.t1 = new Cat () ; // this would have to work
dogs.t1.Bark () ; // oops, t1 is a cat now
Just to expand on Anton Tykhyy's answer,
Yes, you could achieve this with C# 4, provided that you are willing/able to make the following change to your IFile interface:
interface IFile<out T1, out T2> where T1 : IMyInterface where T2 : IMyInterface
{
Int64 prop1 { get; set; }
T1 t1 { get; }
T2 t2 { get; }
}
I've added the out keyword to the generic parameters, and I've removed the set; from the t1 and t2 properties.
Why just not access x.T1 and x.T2 and then cast both to IMyInterface?
foreach (IFile<TItem1, TItem2> x in list)
{
var t1 = x.T1 as IMyInterface;
var t2 = x.T2 as IMyInterface;
}
I think you're confusing the generic constraits with inheritance. The one has nothing to do with the other. The constraints on the generic interface are compiler instructions that tell the compiler that the generic arguments must meet a specific requirment. Logically, to us, that means that ClassSomething definitely has an implementation of IMyInterface. But that's us, the compiler doesn't translate those constraints to any kind of inheritence mapping, so it still only knows that it's an instance of ClassSomething which implements IFile<ClassA, ClassB>. So it won't let you directly cast that to IFile<IMyInterface, IMyInterface>.