Consider the following:
public interface ITree<X>
{
...
ITree<X> Union(ITree<X> other);
...
}
The idea is that I'm going to implement several types of tree. However, the Union() method only works if you try to union two trees of the same type. The type signature above does not enforce this restriction, however.
So, my question is: How can I write a type signature for Union() such that the other argument must have the same type as this?
(Obviously I can do a dynamic run-time test and throw an exception if the types don't match. But I would much, much rather to check this at compile-time if it can be done...)
There isn't a particularly clean way of expressing this, this is a consequence of using interfaces, since there's no way to know the implementing type of ITree<X>. The best method is probably to create another class/interface which constrains the concrete tree type and does the operation(s) you require:
public interface ITreeUnion<T, X> where T : ITree<X>
{
T Union(T left, T right);
}
you'll then have to pass instances of this interface type to where you need to carry out the required operation.
If you really require Union to go on the interface you can use a recurring template:
public interface ITree<T, X> where T : ITree<T, X>
{
T Union(T other);
}
public class RedBlackTree<T> : ITree<RedBlackTree<T>, T>
{
public RedBlackTree<T> Union(RedBlackTree<T> other)
{
}
}
According to your requirment, you would need a generic declaration of Union().
interface
public partial interface ITree<X> {
T Union<T>(T other) where T: ITree<X>;
}
sample classes
public partial class TreeOfObject: ITree<object> {
public T Union<T>(T other) where T: ITree<object> {
return default(T); // sample only; shuold be implemented yourself
}
}
public partial class TreeOfInt: ITree<int> {
public T Union<T>(T other) where T: ITree<int> {
return default(T); // sample only; shuold be implemented yourself
}
}
test
public static partial class TestClass {
public static void TestMethod() {
var x=new TreeOfObject();
var y=new TreeOfInt();
var xx=x.Union(x);
var yy=y.Union(y);
var xy=x.Union(y); // won't compile
var yx=y.Union(x); // won't compile
}
}
Why do you need the interface then? Simply implement a Replace method on each implementation of a tree:
public class RedBlackTree<T> {
public RedBlackTree<T> Union(RedBlackTree<T> other) { ... }
}
public class SplayTree<T> {
public SplayTree<T> Union(SplayTree<T> other) { ... }
}
Since you're looking for compile-time safety when dealing with each implementation of ITree, I would argue you just need to deal with the concrete types. Of course, you could have an ITree<T> with other methods on it if you require.
Somehow, the following actually compiles:
public interface ITree<TSelf, TItem> where TSelf : ITree<TSelf, TItem>
{
TSelf Union(TSelf other);
// ...
}
public class AvlTree<TItem> : ITree<AvlTree<TItem>, TItem> {
public AvlTree<TItem> Union(AvlTree<TItem> other) {
return other;
}
}
Of course it's not particularly useful, since then you'd have to declare variables as ITree<AvlTree>, at which point you might as well not use the interface. With C# generics, the values of generic type parameters have to be known at some point to reify the generic type.
Related
I'm trying to do the following:
public class A
{
}
public class B
{
}
Somewhere along the project I want to have this:
public class C
{
public T func<T>(T obj) [where T can be either of class A or class B]
{
obj.x = 100;
return obj;
}
}
I've been trying:
public T func<T>(T obj) where T: A, B
but this gives me:
The type class constraint 'B' must come before any other constraint.
Can someone explain me how to make func accept only class A or class B?
Exactly as it's described in the question, this job is better handled by overload resolution:
public class C
{
public A func(A obj)
{
obj.x = 100;
return obj;
}
public B func(B obj)
{
obj.x = 100;
return obj;
}
}
But I understand that A and B may be placeholders for any number of types, and it could get tedious to account for them all. In that case, you'll need a common interface that's supported by each of your classes:
interface IBase
{
int x;
}
public class C
{
public IBase func(IBase obj)
{
obj.x = 100;
return obj;
}
}
Note that at this point we still have no need of generics. Additionally, you may need to support a number of types that won't all fit together under a common interface. In this case, still build the interface and put as many types with that interface as possible. If needed, build another interface for a few more types ... and so on... and then between interfaces and specific types you can handle things with overload resolution.
You need some kind of common base for both the classes, either have them implement the same interface as the below code or have them inherit from same class. You can not have a generic constrained to 2 types.
public interface IFooBar
{
void DoThis();
}
public class Foo : IFooBar
{
public void DoThis()
{
//Do something
}
}
public class Bar : IFooBar
{
public void DoThis()
{
//Do something
}
}
public class C
{
public T func<T>(T obj) where T : IFooBar
{
obj.DoThis();
return obj;
}
}
The generics classes are just like any other class, you can't (and shouldn't) have multiple inheritance of classes, you can inherit one class and multiple interfaces.
in your case you should apply an interface on both classes and restrict the generics on that interface.
you can see some documentation in:
Constraints on Type Parameters (C# Programming Guide)
interface IMarkerInterface{} // there is a such pattern called marker
// interface . No need to have methods if there
// is no need for, A and B can just implement it
public class A: IMarkerInterface
{
}
public class B: IMarkerInterface
{
}
public class C
{
public T func<T>(T obj).Where T:IMarkerInterface
{
obj.x = 100;
return obj;
}
}
public T func<T>(T obj) where T: A, B this means T should extend both A and B , but multiple inheritance is not valid in C# ,so it won't work.
You could do one of the following though :
you could make A and B have a common parent via an interface or an abstract class , but that would be code modification.
since both A and B have a default no-arg constructor you could use where T: new().
Also, you can not do obj.x = 100; as there is no way to guarantee thatT will have a instance variable x.
I'm writing an SDK which has an OOP structure for implementing data types;
first an interface
then an abstract implementation
finally an abstract generic implementation
People can choose to implement either the interface, or derive from either of the classes.
public interface IGoo
{
IGoo Duplicate();
...
}
public abstract class Goo : IGoo
{
IGoo IGoo.Duplicate() {
return Duplicate();
}
abstract public Goo Duplicate();
...
}
public abstract class Goo<T> : Goo
{
abstract public Goo<T> Duplicate(); ??????
...
}
I'd like to re-implement the Duplicate method so that it always returns the most specific type possible. I.e. when you call Duplicate on an IGoo instance, you get another IGoo. If you call it on Goo, you get Goo, if you call it on -say- Goo<int>, you get Goo<int>. And all Duplicate() methods always call the most specific implementation.
Is this possible? Is it only possible when you can implement an interface explicitly? In which case, should I not make Goo<int> derive from Goo, but have it implement IGoo instead and type all the low-level functionality twice?
What about the following?
public interface IObj
{
IObj Duplicate();
}
public abstract class Obj : IObj
{
public Obj()
{
}
public virtual IObj Duplicate()
{
return this;
}
}
public abstract class ObjT<T> : Obj
{
public ObjT()
{
}
public override IObj Duplicate()
{
return this;
}
}
public class ObjImpl : Obj
{
}
public class ObjTImpl : ObjT<int>
{
}
I understand that you want it to return the most specific type possible in any inheriting class but it actually is. It's boxing the inheriting type into the interface (or a raw object if you where to return objects instead of interface types. If you run the following test in a console app you will see the proper type is represented:
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
ObjImpl a = new ObjImpl();
ObjTImpl b = new ObjTImpl();
Console.WriteLine(a.Duplicate().GetType());
Console.WriteLine(b.Duplicate().GetType());
Console.ReadLine();
}
}
}
// outputs:
// ObjImpl
// ObjTImpl
The idea of redefining abstracts of abstracts goes against the purpose of abstract polymorphism. If the derived types do not intend to implement the inherited abstract member, they should not be inheriting it.
Although the example I gave above would require casting to access any child class-specific members, it would be the proper way to do it in this approach. The runtime needs to know what types it should expect to deal with.
There is always dynamics you could play around with but to be honest I haven't played around with dynamics with generics and inheritance as I suspect I would make my compiler cry, and when it cries, I cry, a little bit deep down inside... lol
It is only possible when you implement the interface explicitly. That's because the return type of a method is not part of its signature - which the compiler checks when overloading. Therefore, otherwise identical methods which only differ in their return type are syntactically not possible.
I've tried to develop a generic class "MinHeap(T)" implementing IComparable. It works fine when generic is "int" or another class "Code". Going further and using for T a generic class "Node(Code)"
leads to the error mentioned below.
I'm probably too new and not understanding subtle differences between IComparable and IComparable(T). Does someone have an idea ?
Thanks in advance for your help,
LJ
public class MinHeap<T> where T : IComparable
{
...
}
public class Node<T> where T : IComparable
{
T data
...
public int CompareTo(object obj)
{
Node<T> otherNode = obj as Node<T>;
return this.data.CompareTo(otherNode.data);
}
...
}
public class Code : IComparable
{
public int freq;
...
public int CompareTo(object obj)
{
Code otherCode = obj as Code;
return this.freq.CompareTo(otherCode.freq);
}
}
static void Main(string[] args)
{
MinHeap<int> hInt = new MaxHeap<int>(heapSeed); // works fine
MinHeap<Code> hCode = new MinHeap<Code>(codeList); // works fine
...
Node<Code>[] nodeCodeList = new Node<Code>[freqList.Length]; // ok
MinHeap<Node<Code>> h = new MinHeap<Node<Code>>(nodeCodeList); // Error
...
}
Error message:
Error 2 The type 'Algorithms.Node(Algorithms.Code)' cannot be used as type parameter 'T' in the generic type or method 'Algorithms.MinHeap(T)'. There is no implicit reference conversion from 'Algorithms.Node(Algorithms.Code)' to 'System.IComparable'.
The class Node<T> does not implement IComparable. It just haves a constraint for the type of T.
It looks like you've tried to implement the decorator pattern. Implement the interface as well and then map the methods to the decorated object.
You're probably better off defining your generic class so that it doesn't require the type to implement IComparable<T>. That's how the .NET generic classes are implemented. They will use the default comparison for the type, or use the IComparer<T> that you pass in. For example, SortedList has these constructors (among others):
SortedList<TKey, TValue>(); // uses default comparer for TKey
SortedList<TKey, TValue>(IComparer<T> comparer); // uses supplied comparer
It's easy enough to implement:
public class MinHeap<T>
{
private IComparer<T> _comparer;
public MinHeap<T>(IComparer<T> comp)
{
_comparer = comp;
}
public MinHeap<T>()
: this(Comparer<T>.Default)
{
}
}
That way, your clients can use MinHeap<T> to hold instances of classes that do not implement IComparable<T>.
When you do your comparisons, you call _comparer.Compare(item1, item2)
On another note, there's no particular need for your heap to require a node. You can implement a binary heap in an array. See, for example, A Generic BinaryHeap Class.
You should implement IComparable interface within Node class, like this:
public class Node<T>: IComparable<Node<T>> // <- IComparable<Node<T>> implemented
where T: IComparable {
T data;
...
#region IComparable<Node<T>> Members
// interface implementation, not just a method
public int CompareTo(Node<T> other) {
// Let us be accurate with possible nulls:
if (Object.ReferenceEquals(null, other))
return 1; // <- or -1 if you think it's right
else if (Object.ReferenceEquals(data, other.data))
return 0;
else if (Object.ReferenceEquals(null, data))
return -1; // <- or 1 if you think it's right
return data.CompareTo(other.data);
}
#endregion IComparable<Node<T>> Members
}
depending on algorithm of min heap, you may have to implement IComparable> in MinHeap class as well
I'm approaching a problem while still having some ignorance regarding Generics and their proper declarations / uses. I get the premiss, but some of the ins-n-outs of generics still elude me.
Given the following code (does not compile and contains code-smell):
public interface IUIConcern<out T> where T : IUIConcernExtension
{
string Name { get; }
Func<T> Extend();
}
public class UIConcern
{
public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns{
get {
// Logic...
}
set {
// Logic...
}
}
}
... I have a few questions:
Why do I have to specify this part public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
with a constraint when I have already constrained the T in the declaration public interface IUIConcern<out T> where T : IUIConcernExtension
How can I have a property that holds a List<> of my IUIConcern<T> without knowing T other than knowing it will be derived from IUIConcernExtension?
Again, I realize this doesn't compile and is not correct, just looking to see how I can hold a list of generic items that may have many different type of IUIConcern<> elements.
Thank you!
You need to have a base interface, for instance:
public interface IUIConcern
{
string Name { get; }
}
public interface IUIConcern<out T> : IUIConcern where T : IUIConcernExtension
{
Func<T> Extern();
}
How you would define Concerns and Register would depend on how you treat T. Alternatively if you only deal with instances where you know T, you could use a Dictionary<Type, List<IUIConcern>> to hold anything, or potentially drop the base interface and just store using object depending on what you need in your controller code.
The problem is not located at the interface, but the problem is because of your generic implementation using static methods and properties.
The answer from Guvante was correct when saying that you need to define the IUIConcernExtension, but that is of course very logical, so im assuming you have just omitted that part since it does not matter for the issue you are facing.
The problem in the code is that you have created a class that has static methods and procedures, with the generic definition not laying at class level, but at methods level, because of this, the property that has and the Method cannot assume you are always with the same type!!
Lets say you call call :
Register<string>("something", UIConcern<string>)
but before that you have already called:
Register<Type>("something", UIConcern<Type>)
How could the compiler allows you to that?! So the answer is to define the generic type at class level, with this all properties and methods will be of same .
Also you need to use a private member for your list, since you doing everything static, the correct code should be:
interface IUIConcernExtension
{
string Name { get; }
}
public interface IUIConcern<out T> where T : IUIConcernExtension
{
Func<T> Extend();
}
public class UIConcern<T> where T : IUIConcernExtension
{
private static List<IUIConcern<T>> _Concerns = new List<IUIConcern<T>>();
public static void Register(string concernName, IUIConcern<T> uiConcern)
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns
{
get { return _Concerns; }
set { _Concerns = value; }
}
}
I'm curious to know why the implementation of my interface in the abstract base class does not satisfy the the requirements in sub-classes. Here's an example:
public interface IBase { }
public interface IConcrete : IBase { }
public interface IBaseManager<out T>
where T : IBase
{
T Create();
IEnumerable<T> SelectAll();
}
public interface IConcreteManager : IBaseManager<IConcrete> { }
public abstract class Base : IBase { }
public class Concrete1 : Base, IConcrete { }
public abstract class BaseManager<T> : IBaseManager<T> where T : class, IBase
{
#region IBaseManager<T> Members
public T Create()
{
throw new NotImplementedException();
}
public IEnumerable<T> SelectAll()
{
throw new NotImplementedException();
}
#endregion
}
public class ConcreteManager : BaseManager<Concrete>, IConcereteManager
{
//error occurs here
}
This is the error that is being generated:
'ConsoleApplication4.ConcreteManager' does not implement interface member 'ConsoleApplication4.IBaseManager<ConsoleApplication4.IConcrete>.Create()'.
'ConsoleApplication4.BaseManager<ConsoleApplication4.Concrete>.Create()' cannot implement 'ConsoleApplication4.IBaseManager<ConsoleApplication4.IConcrete>.Create()' because it does not have the matching return type of 'ConsoleApplication4.IConcrete'.
If I add these methods to the ConcreteManager class, everything is fine and the compiler is happy.
public new IConcrete Create()
{
return base.Create();
}
public new IEnumerable<IConcrete> SelectAll()
{
return base.SelectAll();
}
If simply returning what the methods from the base class return is sufficient, why do the methods have to be added? Why can't the compiler call the methods in the base class?
As John points out correctly, the C# language does not support return type covariance. Neither does the CLR, so even if the language supported it, the only way we could actually implement the feature would be to silently generate exactly the code you've had to add yourself.
The small benefit afforded to developers of avoiding having to write those stub methods really does not justify the considerable cost of doing the more general covariance feature, so we've never done it.
It looks like you're assuming return type covariance, since ConcreteManager (as an IConcreteManager) expects both Create() and SelectAll() methods with a return type of IConcrete and IEnumerable<IConcrete> respectively, which the base class does not provide.
You are getting those errors because C# does not support return type covariance.
When you implement an interface/abstract class, you must use the same signature. See here
Don't let the generics throw you off, this is no different than if there were no generics.