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
Related
Lets say I have an object of type Foo, which when initialized, will be immutable. Since these objects are immutable, and I want to be able to access any of these Foo objects, I initialize and store these objects in a static class (FooHandler) which contains a list of all the Foo objects.
Currently however, if a class wants to access this object, I give them the index of where the Foo object is located in the list in FooHandler, and have a getter method to return the object itself when needed. The intent of this is to save on memory by not having two of the same objects in circulation (which I consider a waste).
Is there a better approach in C# for referencing these objects (like a pointer or something similar) or a better structure entirely for how to approach this problem, as I feel giving an index to an immutable object is too hackish and error prone?
Example code:
public class Foo {
public int A { get; private set; }
public int B { get; private set; }
public Foo(int a, int b) {
A = a;
B = b;
}
}
public static class FooHandler {
private static List<Foo> fooList;
static FooHandler() {
fooList = new List<Foo>();
fooList.Add(new Foo(1, 2));
fooList.Add(new Foo(3, 4));
}
// Assume there is error checking
public static Foo GetFoo(int index) {
return fooList[index];
}
}
public class Bar {
public int FooID { get; private set; }
public Bar(int fooID) {
FooID = fooID;
}
public void func() {
Console.WriteLine(FooHandler.GetFoo(FooID).A);
}
}
Note: I know this example could be considered mutable, just wanted to type something up quickly without too much testing.
C# already passes around reference types (denoted by class) with a reference (roughly equivalent to a pointer).
You need not do anything special to get this and it happens automatically. There is no waste in just returning the Foo directly.
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];
}
}
How can I access an element by index of a member List via a property? For example:
public class foo{
private List<type> list = new List<type>;
public List{
get{/*basically, what goes here?*/}
}
}
//Much later....
foo Foo = new foo();
Console.WriteLine(Foo.List[1]);
One thing to consider is what ability you want to provide to update the list. If you just expose the list as a get-only property, then there's nothing stopping someone from modifying the list:
public class foo{
private List<type> list = new List<type>;
public List<type> List{
get{return list}
}
}
//Much later....
foo Foo = new foo();
Foo.List.Clear(); // perfectly legal
If, however, you want a "read-only" list exposed, then you can expose the list as read-only:
public class foo{
private List<type> list = new List<type>;
public IList<type> List{
get{return list.AsReadOnly()}
}
}
//Much later....
foo Foo = new foo();
Foo.List.Clear(); // not possible
EDIT
Based on your comment to another question, it is unclear whether you want to expose the list as a property or access items by index. For the latter you can add an indexer to the class:
public class foo{
private List<type> list = new List<type>;
public type this[int i]{
get{return list[i]}
get{list[i] = value}
}
}
//Much later....
foo Foo = new foo();
Console.WriteLine(Foo[1]);
Since you already have a list, you can just return that list in the property
public class foo{
private List<type> list = new List<type>;
public List<type> List{
get{ return list; }
}
}
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?