I'm trying to accomplish something like this.
public class GreatClass<A, B>
where A : IA
where B : IB, new()
{
public void Function()
{
var list = new List<A>();
var obj = new B { Items = list.ToArray() };
}
}
public interface IA
{
}
public interface IB
{
IA[] Items { get; set; }
}
namespace Namespace1
{
public class A : IA {}
public class B : IB {}
}
namespace Namespace2
{
public class A : IA {}
public class B : IB {}
}
So I have two namespaces with similar classes which implements the same interface. I have some logic which I want to share between the classes in the two namespaces and am therefore using generic classes which implements the implemented interface.
However I get a compile error on "list.ToArray()" stating that it Cannot implicitly type 'A[]' to 'IA[]'. Is there something I can do which makes the compiler understand how to handle this?
Using .Cast() like a few of you have been suggesting gives me a runtime error instead. That I can't convert type IA[] to Namespace1.A[] (or Namespace2.A[]).
There are several options, but the best one is to strongly type your B class and make it generic.
This is the code that will do. Note that TA is the type of A you are passing in, thus always allowing to access the members strongly typed.
public interface IB<TA> where TA : IA
{
TA[] Items { get; set; }
}
And change GreaterClass to this:
public class GreatClass<A, B>
where A : IA
where B : IB<A>, new()
{
}
Simply declare your list like this:
var list = new List<IA>();
Related
Here it is:
abstract class IA
{
public virtual void ChangePropertyOfAIChild()
{
b.value = true;
}
}
...
class B:IA
{
bool value;
}
class C:IA
{
bool value;
}
....
///main
IA newBInstance = new B();
newBInstance.ChangePropertyOfAIChild();
IA newCInstance = new C();
newCInstance .ChangePropertyOfAIChild();
/////
What would be a proper way of calliing an already implememnted function in a child's class from the base abstract class and changing it's value?
Thanks!
As #Camilo Terevinto pointed out, you heirarchy is wrong. try:
public abstract class IA
{
public bool value;
public virtual void ChangePropertyOfAIChild()
{
value = true;
}
}
public class B : IA
{ }
public class C : IA
{ }
// in main
IA newBInstance = new B();
newBInstance.ChangePropertyOfAIChild();
IA newCInstance = new C();
newCInstance.ChangePropertyOfAIChild();
///
Your sample code had the base abstract class trying to change the value of a field in a class it doesn't know about:
(b.value = true)
For the base class to be able to do this, the field needs to be declared inside the base class.
I believe you have't got your inheritance quite right.
If this is your class implementation:
public abstract class IA
{
}
public class B : IA
{
public bool value;
}
public class C : IA
{
public bool value;
}
And then if you create an instance of IA like so:
IA newBInstance = new B();
Then compiler goes ahead and creates an instance of IA. Since your IA does NOT have a property called value, you cannot access it.
You have two options, either use the method suggested by CodexNZ in the previous reply, or simply cast your newInstance to B and directly set value. Like this:
IA newBInstance = new B();
((B)newBInstance).value = true;
However this is counter intuitive since if you can do that you might as well create an instance of B in the first place. So I recommend the previous method. This is more to explain why your logic doesn't work.
Please refer to a tutorial like this to learn more. There are tons of more resources on the internet.
I have the following scenario
public class A
{
}
public class BA : A
{
}
//other subtypes of A are defined
public class AFactory
{
public T Create<T>() where T : A
{
//work to calculate condition
if (condition)
return new BA();
//return other subtype of A
}
}
The following compilation error is thrown:
Error CS0029 Cannot implicitly convert type 'B' to 'T'
What's wrong?
Well the cast could easily fail. Suppose I have:
public class AB : A {}
B b = new B();
AB ab = b.Create<AB>();
That would end up trying to assign a B reference to a variable of type AB. Those are incompatible.
It sounds like you probably shouldn't make Create a generic method. Or maybe you should make A generic:
public abstract class A<T> where T : A
{
public abstract T Create();
}
public class B : A<B>
{
public override B Create()
{
return new B();
}
}
That would work - but we don't know what you're trying to achieve, so it may not actually help you.
Alternatively you could keep your current design, but use:
public T Create<T>() where T : A
{
return (T) (object) new B();
}
That will then fail if you call Create with a type argument of anything other than object, A or B, which sounds a little odd to me...
T can be any class derived from A. There could also be a
class C : A { }
It matches the generic constraint, but you can't return an instance of B from Create<C>() method.
Right. For creating new B class you should use this code:
public class A
{
}
public class B : A
{
public static T Create<T>() where T : A, new()
{
return new T();
}
}
public class Example
{
public void DoWork()
{
B b = B.Create<B>();
A a = B.Create<A>();
}
}
Let's say I have a generic class as follows:
public class GeneralPropertyMap<T>
{
}
In some other class I have a method that takes in an array of GeneralPropertyMap<T>. In Java, in order to take in an array that contains any type of GeneralPropertyMap the method would look like this:
private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}
We use the wildcard so that later we can call TakeGeneralPropertyMap passing a bunch of GeneralPropertyMap with any type for T each, like this:
GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
//And finally pass the array in.
TakeGeneralPropertyMap(maps);
I'm trying to figure out an equivalent in C# with no success. Any ideas?
Generics in C# make stronger guarantees than generics in Java. Therefore, to do what you want in C#, you have to let the GeneralPropertyMap<T> class inherit from a non-generic version of that class (or interface).
public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
// Only you can implement it:
internal GeneralPropertyMap() { }
}
Now you can do:
private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}
And:
GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);
While, as others have noted, there's no exact correspondence to wildcards in c#, some of their use cases can be covered with covariance/contravariance.
public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so
// we need to introduce an interface...
public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class
// inherit from it
//now our method becomes something like
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){}
// and you can do
var maps = new List<IGeneralPropertyMap<Object>> {
new GeneralPropertyMap<String>(),
new GeneralPropertyMap<Regex>()
};
//And finally pass the array in.
TakeGeneralPropertyMap<Object>(maps);
The caveat is that you can't use covariance with value types, so adding a new GeneralPropertyMap<int>() to our list fails at compile time.
cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'
This approach may be more convenient than having a non-generic version of your classes/interfaces in case you want to constrain the types that GeneralPropertyMap can contain. In that case:
public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {}
allows you to have:
var maps = new List<IGeneralPropertyMap<IMyType>> {
new GeneralPropertyMap<A>(),
new GeneralPropertyMap<B>() ,
new GeneralPropertyMap<C>()
};
TakeGeneralPropertyMap(maps);
There is no direct equivalent to this in C#.
In C#, this would often be done by having your generic class implement a non-generic interface or base class:
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
You could then pass an array of these:
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);
Make an interface from the members of GeneralPropertyMap (IGeneralPropertyMap), and then take an IGeneralPropertyMap[] as an argument.
Actually, you can get pretty close to a wildcard by using dynamic. This also works nicely if you have a non-generic superclass.
For example:
public class A
{
// ...
}
public class B<T> : A
{
// ...
}
public class Program
{
public static A MakeA() { return new A(); }
public static A MakeB() { return new B<string>(); }
public static void Visit<T>(B<T> b)
{
Console.WriteLine("This is B with type "+typeof(T).FullName);
}
public static void Visit(A a)
{
Console.WriteLine("This is A");
}
public static void Main()
{
A instA = MakeA();
A instB = MakeB();
// This calls the appropriate methods.
Visit((dynamic)instA);
Visit((dynamic)instB);
// This calls Visit(A a) twice.
Visit(instA);
Visit(instB);
}
}
How this works is explained in the C# documentation here.
I'm writing an application in C#, and am wrestling with its implementation of generics. I have an inheritance hierarchy that is mirrored by another inheritance hierarchy (Models and View Models) like so:
class A_Content { }
class B_Content : A_Content
{
public string Bar;
}
class C_Content : A_Content
{
public string Foo;
}
class A { public A_Content content; }
class B : A { }
class C : A { }
public class Test
{
IList<A> A_Collection = new List<A>();
public Test()
{
B b = new B();
C c = new C();
b.content = new B_Content();
c.content = new C_Content();
A_Collection.Add(b);
A_Collection.Add(c);
}
}
This works well enough, but doesn't enforce any type constraints on content, which leaves me casting it to the proper derived class every time I want to use it. I'd like to coax the compiler into enforcing the constraint that B objects only have B_Content content. My first cut at that was:
class A_Content { }
class B_Content : A_Content
{
public string Bar;
}
class C_Content : A_Content
{
public string Foo;
}
class A { }
class B : A { B_Content content; }
class C : A { C_Content content; }
public class Test
{
IList<A> A_Collection = new List<A>();
public Test()
{
B b = new B();
C c = new C();
A_Collection.Add(b);
A_Collection.Add(c);
}
}
This works nicely, but means that I can't access the common elements of content when all I have is a collection of As. What I'd really like to do is something like:
abstract class A_Content { }
class B_Content : A_Content
{
public string Bar;
}
class C_Content : A_Content
{
public string Foo;
}
abstract class A<T> { T content; }
class B : A<B_Content> { }
class C : A<C_Content> { }
public class Test {
IList<A<A_Content>> A_Collection = new List<A<A_Content>>();
public Test()
{
B b = new B();
C c = new C();
A_Collection.Add(b);
A_Collection.Add(c);
}
}
This, however, produces an error complaining that B cannot be implicitly converted into an A. I've tried adding an explicit cast to no avail. Is there some way to express the constraints I'm looking for more elegantly than the second model?
It's not entirely clear what you're after. Are you trying to make it so that every instance of A has a Content property whose type is A_Content, every B has a Content property that's a B_Content, and so on? If so, you can't do that and have B/C/etc. inherit from A. (not in a non-smelly way, anyway). The signature of A says that the Content property should be able to get (and, presumably, set) any valid value of A_Content. You cannot change the return type of a function or the type of a property or field in a derived class. You could use generics to basically defer the typing of the property all the way down to the usage of the class, but that syntax will be ugly and I'm not certain what it gets you.
For example, you could do this:
public class A<TContent> where TContent : A_Content
{
public TContent Content { get; set; }
}
public class B<TContent> : A<TContent> where TContent : B_Content
{
// nothing here, as the property is already defined above in A
}
public class C<TContent> : A<TContent> where TContent : C_Content
{
// nothing here, as the property is already defined above in A
}
But this means two things:
Anywhere you use A, B, or C you must specify the actual type of TContent (so A_Content, B_Content, etc.). Which is a pain
There is absolutely nothing stopping you from doing something like A<B_Content> (which is, in fact, essentially what B is in this case, since we've added nothing to the class).
In short, I think you need to drop back and punt and come up with a new design.
By the way
The reason your second example doesn't fly (with the List) is because you've told the list that it needs to contain A<A_Content>. Since B<B_Content> doesn't satisfy that, it won't work. This is a typical variance question and it confuses a lot of people. But consider this scenario (this code will not compile; it's intended to be demonstrative of the underlying reason):
List<A<A_Content>> list = new List<A<A_Content>>();
list.Add(new B()); // this seems OK so far, right?
A<A_Content> foo = list[0];
foo.content = new A_Content():
This would obviously break, since foo in reality is a B<B_Content>, so the runtime wouldn't let you set content equal to anything other than an instance of B_Content (or something that inherits from it), but the signature of the class means you should be able to assign anything that'sA_Content` or inherits from it.
You can use an interface for this, along with explicit implementation of the interface's member(s):
abstract class A_Content {}
class B_Content : A_Content {}
class C_Content : A_Content {}
interface IA
{
A_Content content { get; }
}
abstract class A<T> : IA
where T : A_Content
{
T content;
A_Content.content { get { return this.content; } }
}
class B : A<B_Content> {}
class C : A<C_Content> {}
Then you can make a List<IA> to hold a homogeneous collection of B and C objects.
In fact, with C# 4 and higher, you could make the interface generic and covariant; then you can implement the interface implicitly (as long as you use a property rather than a field):
interface IA<out T>
{
T content { get; }
}
abstract class A<T> : IA<T>
where T : A_Content
{
T content { get; set; }
}
class B : A<B_Content> {}
class C : A<C_Content> {}
Now, B still cannot be converted to A<A_Content>, but it can be converted to IA<A_Content>, so you can use a List<IA<A_Content>> to hold your homogeneous collection of objects.
Well, compiler produces an error, because indeed B cannot be converted into A<A_Content>.
This is because A<A_Content> is not a superclass of B. The parent class of B class is A<B_Content>.
I am afraid you need to stick to casting. It is needed here, because you have list of As.
If you really want to avoid casting (I am not sure why you would like to), you can try with dynamic dispatch.
You can try creating a List<dynamic> instead of List<A>.
You will need at least C# 4.0, though.
Hope I right undertsood your intention, so
having a collection like this
IList<A> means that you would like to have a collection of A objects with different implementation scenarios.
That property if the property of a base type. That means that base type has to expose methods/properties => so state and behavior primitives which the child classes has to make a concrete implementation.
Something like this:
class A_Content { public virtual string Bar {get;set;} }
class B_Content : A_Content
{
public override string Bar {get;set;};
}
class C_Content : A_Content
{
public override string Bar {get;set};
}
and somewhere in the code:
public Test()
{
B b = new B();
C c = new C();
A_Collection.Add(b);
A_Collection.Add(c);
//so
A_Collection[0].Bar // B::Bar
A_Collection[1].Bar //C::Bar
}
And you do not need to cast to real object. Simple OOP approach.
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> { }