I have two classes:
public class Foo<T>{}
public class Bar
{
private List<Foo> foos = new List<Foo>();
public Foo GetFoo(int index)
{
return foos[index];
}
}
However, both the list and method say that i need a type parameter for the Foos i specify, but i just want Foos in general, so i could add a Foo< int >, a Foo< float >, a Foo< Baz > etc. etc. to the list, and then have the method return a Foo with an unknown type. And making GetFoo generic is OK if it helps, but I can't figure out how it would.
You could make Foo<T> derive from a base class (or implement an interface) that is non-generic. You could then return a List<IFoo> with the properties that aren't specific to the type T.
This would allow you to have a single list containing any type of Foo<T>.
public abstract class Foo
{
//general foo logic here
}
public class Foo<T>: Foo
{
//generic type specific information here
}
public class Bar
{
private List<Foo> foos = new List<Foo>();
public Foo GetFoo(int index)
{
return foos[index];
}
}
Related
Ok, so here's the basic code:
class foo
{
String name;
int property;
}
class bar
{
private List<foo> a;
private List<foo> b;
}
I'd like to make it so that calling code can iterate over either list but I want to keep them protected from editing. I've looked into implementing the IEnumarable interface but the problem is that it expects a single "GetEnumerable" definition, but I want two different enumerators. For instance, i want to be able to say
foreach(foo in bar.getA())
{ //do stuff }
and then
foreach(foo in bar.getB())
{ //do stuff }
Do I have to subclass each element and implement the IEnumerable interface over each, and then include THOSE as properties? Am I misunderstanding the IEnumerable interface? I know that the List class has it's own Enumerator, so I could do something like
class bar
{
private List<foo> a;
private List<foo> b;
public IEnumerator<foo> getAEnumerator()
{ return a.GetEnumerator();
public IEnumerator<foo> getBEnumerator()
{ return b.GetEnumerator();
}
but then my for loops look like this:
bar x = new bar();
IEnumerator<foo> y = x.getAEnumerator();
while (y.moveNext())
{
foo z = y.Current;
}
so I lose the readability of "foreach".
Is there a way to accomplish using "foreach" over these lists without exposing these lists publicly? I'm still trying to get my head around the IENumerable interface, so maybe I'm missing something obvious.
Don't expose a List<T>, expose something else, like an IReadOnlyList<T> instead:
class bar
{
private readonly List<foo> a = new List<foo>();
private readonly List<foo> b = new List<foo>();
public IReadOnlyList<foo> A { get; private set; }
public IReadOnlyList<foo> B { get; private set; }
public bar()
{
A = a.AsReadOnly();
B = b.AsReadOnly();
}
}
Any changes to a and b will reflect in A and B.
Also note that while you can cast a List<T> to an IReadOnlyList<T>, the calling code can cast it back to List<T>. The above method returns a ReadOnlyCollection<T> which provides a safeguard against casting back to a mutable collection type.
The readonly keyword only ensures you don't substitute references to a and b with something else later on.
class bar
{
private readonly List<foo> a = new List<foo>();
private readonly List<foo> b = new List<foo>();
public IReadOnlyList<foo> A { get {return a.AsReadOnly();}}
public IReadOnlyList<foo> B { get {return b.AsReadOnly();}}
}
this way you'll not even have to initialize it, and no need to any kind of set
Here's my best attempt to recreate the situation.
public interface IFoo
{
}
public class Foo : IFoo { }
public class Bar : IFoo { }
public class CollectionOf<T> : List<IFoo>
{
}
public class Bars : CollectionOf<Bar>
{
}
public class Test
{
public void Test()
{
CollectionOf<IFoo> bars = new Bars();
}
}
Compiler complains on the instantiation. Bars is a collection of IFoos. Is this one of those covariance/contravariance issues?
Yes.
Think about it for a second; bars should legally be able to hold objects of any type that implement IFoo. However, an object of type Bars can only hold objects of type Bar.
Using your code this would be allowed, which is obviously wrong.
CollectionOf<IFoo> bars = new Bars();
bars.Add( new Foo() ); // Uh oh!
That would effectively break the type safety afforded to you via generics.
Yes it is.
If this was allowed, you would be able to place any object into that collection, as long as it implemented the IFoo interface, but that wouldn't be safe for the collection.
Let me illustrate:
var b = new Bars();
CollectionOf<IFoo> bars = b;
bars.Add(Dummy); // implements IFoo, but does not descend from Bar
At this point, what does b contain? An object of type Dummy? That would be bad, and thus this is not allowed in the first place.
The fix, if there is one would depend on what it is that's not working for you. I can get your example to compile in two ways, either use IEnumerable or define your CollectionOf as an interface with the out generic modifier. Whether either is a fix for you I don't know:
public interface IFoo { }
public class Foo : IFoo { }
public class Bar : IFoo { }
public interface CollectionOf<out T> : IEnumerable<IFoo> { }
public class Bars : CollectionOf<Bar> { }
public class Test
{
public void Test()
{
IEnumerable<IFoo> bars1 = new Bars();
CollectionOf<IFoo> bars2 = new Bars();
}
}
Considering the following case in C#:
class Foo
{
public Foo() { }
}
class Foo2
{
private List<Foo> m_List = new List<Foo>();
public Foo2() { m_List.Add(new Foo); }
}
Foo2 fooInstance = new Foo2();
Foo2 owns a List that contains a Foo - is there any built-in way for the Foo to figure out which List it's contained in, and which object that list belongs to? In other words, can Foo obtain a reference to Foo2, or do I have to add an explicit backwards reference in Foo - pointing to Foo2 - as I've been doing?
No, there's no built-in way. Instances of Foo only know about themselves, the public interface of their members, and the public/protected interface of their base class, if they have one.
If you give a little more context about what you're trying to do, I may be able to offer you an alternative solution.
Foo will have no knowledge that it is contained within a list unless you specify that somehow. A list after all is just a set of references to a location in memory. There is no relationship from a pointer to what contains the pointer.
class Foo
{
public Foo2 Parent { get; protected set; }
public Foo(Foo2 parent)
{
Parent = parent;
}
}
class Foo2
{
public Foo2()
{
List<Foo> x = new List<Foo>
{
new Foo(this)
};
}
}
No; that's inherently impossible.
What if you put the same object in two lists?
I've got this class:
class Foo {
public string Name { get; set; }
}
And this class
class Foo<T> : Foo {
public T Data { get; set; }
}
Here's what I want to do:
public Foo<T> GetSome() {
Foo foo = GetFoo();
Foo<T> foot = (Foo<T>)foo;
foot.Data = GetData<T>();
return foot;
}
What's the easiest way to convert Foo to Foo<T>? I can't cast directly InvalidCastException) and I don't want to copy each property manually (in my actual use case, there's more than one property) if I don't have to. Is a user-defined type conversion the way to go?
You can create an explicit conversion from Foo within Foo<T>.
class Program
{
static void Main()
{
Foo foo = new Foo();
foo.Name = "Blah";
Foo<int> newfoo = (Foo<int>)foo;
Console.WriteLine(newfoo.Name);
Console.Read();
}
}
class Foo
{
public string Name { get; set; }
public object Data { get; set; }
}
class Foo<T>
{
public string Name { get; set; }
public T Data { get; set; }
public static explicit operator Foo<T>(Foo foo)
{
Foo<T> newfoo = new Foo<T>();
newfoo.Name = foo.Name;
return newfoo;
}
}
Edit: This only works without inheritance. It appears you are not able to do a user-defined conversion from a base to a derived class. See comments from Mads Torgersen here http://social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/14cf27cf-b185-43d6-90db-734d2ca3c8d4/ :
We have taken the liberty of
predefining conversions (casts)
between base classes and derived
classes, and to make the semantics of
the language predictable we don't
allow you to mess with it.
It looks like you may be stuck with defining a method to turn a Foo into a Foo<T>. That, or drop the inheritance. Neither solution sounds particularly ideal.
If you are getting an InvalidCastException, the Foo type returned by GetFoo() is not Foo<T>. You will need to either pass T or typeof(T) to that function so it can return an instance of Foo<T>.
Use copy constructors. Foo implements:
class Foo {
Foo(Foo copy) { ... }
}
while Foo shall be constructed using the following:
class Bar<T> : Foo {
Bar(Foo copy) : base(copy) { ... }
}
...Yes. You need to copy member by member, and this should be done in "copy constructor".
Suppose I write a library with the following:
public class Bar { /* ... */ }
public class SomeWeirdClass<T>
where T : ???
{
public T BarMaker(Bar b)
{
// ... play with b
T t = (T)b
return (T) b;
}
}
Later, I expect users to use my library by defining their own types which are convertible to Bar and using the SomeWeirdClass 'factory'.
public class Foo
{
public static explicit operator Foo(Bar f)
{
return new Bar();
}
}
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
Foo f = weird.BarMaker(b);
}
}
this will compile if i set where T : Foo but the problem is that I don't know about Foo at the library's compile time, and I actually want something more like where T : some class that can be instantiated, given a Bar
Is this possible? From my limited knowledge it does not seem to be, but the ingenuity of the .NET framework and its users always surprises me...
This may or not be related to the idea of static interface methods - at least, I can see the value in being able to specify the presence of factory methods to create objects (similar to the same way that you can already perform where T : new())
edit: Solution - thanks to Nick and bzIm - For other readers I'll provide a completed solution as I understand it:
edit2: This solution requires Foo to expose a public default constructor. For an even stupider better solution that does not require this see the very bottom of this post.
public class Bar {}
public class SomeWeirdClass<T>
where T : IConvertibleFromBar<T>, new()
{
public T BarMaker(Bar b)
{
T t = new T();
t.Convert(b);
return t;
}
}
public interface IConvertibleFromBar<T>
{
T Convert(Bar b);
}
public class Foo : IConvertibleFromBar<Foo>
{
public static explicit operator Foo(Bar f)
{
return null;
}
public Foo Convert(Bar b)
{
return (Foo) b;
}
}
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
Foo f = weird.BarMaker(b);
}
}
edit2: Solution 2: Create a type convertor factory to use:
#region library defined code
public class Bar {}
public class SomeWeirdClass<T, TFactory>
where TFactory : IConvertorFactory<Bar, T>, new()
{
private static TFactory convertor = new TFactory();
public T BarMaker(Bar b)
{
return convertor.Convert(b);
}
}
public interface IConvertorFactory<TFrom, TTo>
{
TTo Convert(TFrom from);
}
#endregion
#region user defined code
public class BarToFooConvertor : IConvertorFactory<Bar, Foo>
{
public Foo Convert(Bar from)
{
return (Foo) from;
}
}
public class Foo
{
public Foo(int a) {}
public static explicit operator Foo(Bar f)
{
return null;
}
public Foo Convert(Bar b)
{
return (Foo) b;
}
}
#endregion
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo, BarToFooConvertor> weird = new SomeWeirdClass<Foo, BarToFooConvertor>();
Foo f = weird.BarMaker(b);
}
}
Sounds like you found a solution to the larger problem. To answer your specific question: no, neither C# nor the CLR support the "backwards" generic type parameter constraint. That is,
class C<T> where Foo : T
"T must be Foo or a type which Foo converts to" is not supported.
There are languages that have that sort of constraint; IIRC Scala is such a language. I suspect this feature would be handy for certain uses of contravariant interfaces.
I don't think there is necessarily a syntactically cool way to do this built into the language. One possible solution to your problem could be to define a convertible interface:
public interface IConvertible<T>
where T : new() // Probably will need this
{
T Convert();
}
Then your class could be:
public class Foo : IConvertible<Bar>
{
}
I think this gets you close to where you want to be... All the Foo's and Bar's in your question sometimes make it hard to determine exactly what your intent is. Hope this helps.
Edit: Added where constraint... you will probably have to be able to create a new instance in your convertible class.
Edit 2: Made Foo inherit from ICovertible<Bar>
You could make a detour via an interface which is used as a type constraint.
For example, where T : IComparable<U> is used to constrain the type to something that can be compared to another thing, which must express this ability by implementing IComparable<another>. If you had an interface ICastableFrom<T>, you could achieve what you want by forcing them to implement ICastableFrom<Bar>.
Rather than go through the trouble of defining an interface and modifying your class to implement that interface, why not just do this?
public class SomeWeirdClass<T>
{
// aside: why is this method called 'BarMaker' if it returns a T?
public T BarMaker(Bar b, Func<Bar, T> converter)
{
// ... play with b
return converter(b);
}
}
Then in the event that you are dealing with an object of a type T to which Bar can be directly cast, this method could be called simply as follows:
var someWeirdObject = new SomeWeirdClass<Foo>();
var someBar = new Bar();
var someFoo = someWeirdObjcet.BarMaker(someBar, bar => bar as Foo);
By the way (since the Func<T, TResult> delegate emerged in .NET 3.5), you could also use Converter<TInput, TOutput> (which is exactly the same) for the converter parameter.