.NET Forum / Languages / C# / March 2008
Deriving from IList question
|
|
Thread rating:  |
Bart - 26 Mar 2008 00:40 GMT Hi all,
I have created a class which derives fron IList.
It looks like this:
public class Signals<Signal>: IList<Signal>
But I don't know how to impement the next section.
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
#endregion
How should I implent this. Can someone give me an example ?
Thanks in advance,
Bart
Peter Duniho - 26 Mar 2008 00:48 GMT > [...] > But I don't know how to impement the next section. [quoted text clipped - 6 lines] > > How should I implent this. Can someone give me an example ? You probably are looking for something like this: http://msdn2.microsoft.com/en-us/library/dscyy5s0.aspx
It documents implementation of iterators in C#.
Pete
Bart - 26 Mar 2008 01:02 GMT Hi Peter,
Thanks for your quick answer.
In my class I create a private list. Can I just return _list.GetEnumerator()
Sorry for the probably dumb question :(
Bart
>> [...] >> But I don't know how to impement the next section. [quoted text clipped - 13 lines] > > Pete Peter Duniho - 26 Mar 2008 01:25 GMT > In my class I create a private list. Can I just return > _list.GetEnumerator() > > Sorry for the probably dumb question :( No need to apologize. There are dumb ways to ask a question, but there are no dumb questions.
As for whether you can delegate the retrieval of an enumerator to a contained IList implementation, sure. That's a perfectly acceptable implementation, especially if your own class is acting as a collection but is essentially delegating all of the other collection behaviors to that same IList.
Pete
Marc Gravell - 26 Mar 2008 08:21 GMT For the record - alternative approaches might be to inherit from Collection<T> or List<T> (the first offers more extension points) and just add the functionality you need... something like below. This then given you standard IList/IList<T> etc for free:
public sealed class Signals : Collection<Signal> { protected override void InsertItem(int index, Signal item) { CheckValid(item); base.InsertItem(index, item); } protected override void SetItem(int index, Signal item) { CheckValid(item); base.SetItem(index, item); } void CheckValid(Signal item) { if (item.Foo < 0) throw new InvalidOperationException("Foo must be non-negative"); } }
Bart - 26 Mar 2008 18:38 GMT Another question about this.
I did try to derive from List<T> and Collection<T> but I was not able to override for example the Add method. I am happy the way it is implemented it right now.
But one thing I can't accomplish and could need some more help with it. In the method add I want to show a messagebox with the signal name like this:
public void Add(Signal item) { MessageBox.Show(item.Name); _list.Add(item); }
But I can't compile this and I don't understand why item is not of type Signal. Even casting it to a Signal didn't do the trick.
So can someone show me how I could to this.
Thanks again,
Bart
Peter Duniho - 26 Mar 2008 18:59 GMT > [...] > public void Add(Signal item) [quoted text clipped - 5 lines] > But I can't compile this and I don't understand why item is not of type > Signal. Even casting it to a Signal didn't do the trick. Without a more complete code sample and the exact text of the compiler error, it's hard to say what might be going wrong.
However, if you're inheriting List<T> directly, I'm not clear on why you still have a "_list" member. By inheriting List<T>, your own class "becomes" the list. You shouldn't need a private "_list" to store the data at that point.
Pete
Peter Duniho - 26 Mar 2008 19:00 GMT > [...] > But I can't compile this and I don't understand why item is not of type > Signal. Even casting it to a Signal didn't do the trick. Forgot to add...
Note also that the Add() method isn't virtual, so you can't override it anyway. If you have the need to provide your own behavior, it may in fact be better to do this the way you were before, with composition rather than inheritance.
Pete
Bart - 27 Mar 2008 00:22 GMT > Note also that the Add() method isn't virtual, so you can't override it > anyway. If you have the need to provide your own behavior, it may in fact > be better to do this the way you were before, with composition rather than > inheritance. That's exactly the reason why I choose for composition. Anyway the constructor for my Signals get a reference to a validator. This validator should validate the Signal item.
Sore here is the most important peace of the code I hope you could help me out here. Thanks again.
public class SignalValidator { public bool Validate(Signal signal) { return true; // True for the moment !!! } } ------------------------------------------------------- public class Signal { private int _number; private string _name; private string _comment;
public Signal() { }
public Signal(int Number, string Name, string Comment) { _number = Number; _name = Name; _comment = Comment; }
public int Number { get {return _number ;} set { _number = value;} }
public string Name { get{ return _name;} set{ _name = value;} }
public string Comment { get{ return _comment; } set{ _comment = value; } } } -------------------------------------------------------------------- public class Signals<Signal>: IList<Signal> { private List<Signal> _list = new List<Signal>();
public Signals(SignalValidator Validator) { _validator = Validator; }
public void Add(Signal item) { if(!_validater.Validate(item)) { Trow new exception(); } else { _list.Add(item); } } }
Regards,
Bart
Bart - 27 Mar 2008 00:28 GMT Sorry forgot the compiler messages:
Error 1 The best overloaded method match for 'SignalList.SignalValidator.Validate(SignalList.Signal)' has some invalid arguments D:\Users\Bart\Visual Studio 2008\Projects\SignalList\SignalList\Signals.cs 65 13 SignalList
Error 2 Argument '1': cannot convert from 'Signal' to 'SignalList.Signal' D:\Users\Bart\Visual Studio 2008\Projects\SignalList\SignalList\Signals.cs 65 33 SignalList
Bart
Peter Duniho - 27 Mar 2008 00:50 GMT >> Note also that the Add() method isn't virtual, so you can't override it >> anyway. If you have the need to provide your own behavior, it may in [quoted text clipped - 10 lines] > me > out here. Thanks again. Well, ignoring for a moment at least three other errors in your code that I see, I think the issue you're running into is here:
> [...] > public void Add(Signal item) [quoted text clipped - 9 lines] > } > } Your SignalValidator class requires that you pass it a Signal. However, your Signals<Signal> class is actually a generic class, with the type parameter named "Signal" not constrained to anything. So when you try to call "_validater.Validate(item) [sic]", the compiler complains because it has no idea at the moment that it's compiling that code that "item" is of type "Signal". It has the type of the generic type parameter _named_ "Signal" but that's the name of the type parameter, not the class actually being used.
I suspect that what you really want is to declare your Signals class like this:
public class Signals : IList<Signal>
If you do that, I think the code will compile (after you fix the other errors).
Alternative solutions would include constraining the type parameter:
public class Signals<T> : IList<T> where T : Signal
Or making the SignalValidator class generic as well:
public class SignalValidator<T> { ... }
public class Signals<T> : IList<T> { private SignalValidator<T> _validator; private List<T> _list = new List<T>();
public Signals(SignalValidator<T> Validator) { _validator = Validator; }
public void Add(T item) { if(!_validator.Validate(item)) { throw new Exception(); } else { _list.Add(item); } } }
Of course, in this last option, it begs the question as to what the generic SignalValidator<T> might do. Since it wouldn't necessarily know anything about the generic type parameter (unless you constrained its type parameter to Signal, when you'd then have to do for the Signals class anyway, obviating the need to make SignalValidator generic in the first place), you would need to provide some sort of validating method for the class. Assuming all the class does is call the validating method, you could do away with the SignalValidator class altogether and just declare a validating method delegate type to be passed to the Signals class instead:
public delegate bool SignalValidator<T>(T t);
public class Signals<T> : IList<T> { private SignalValidator<T> _validator; private List<T> _list = new List<T>();
public Signals(SignalValidator<T> Validator) { _validator = Validator; }
public void Add(T item) { if(!_validator(item)) { throw new Exception(); } else { _list.Add(item); } } }
Then when you instantiate a Signals<T>, you'd simply pass in a method to be used for validation rather than a whole class.
Anyway, as I said...I think what you really want is the first suggestion above. But any of the above should work better than what you've got right now.
Pete
Bart - 27 Mar 2008 18:22 GMT Hi Peter,
Thanks for your answers so far. I must admit that I have to chew on this. But when you don't mind I like to come back on it.
Bart
Peter Duniho - 27 Mar 2008 19:08 GMT > Thanks for your answers so far. I must admit that I have to chew on this. > But when you don't mind I like to come back on it. Of course. No problem. I think the key thing you need to understand is that if you declare a class with the syntax "class MyClassName<SomeIdentifier>", the "SomeIdentifier" becomes the type parameter, and does not reference some other existing type.
It's sort of like declaring a method like this:
public MyClass { } public MyOtherClass { }
void MyMethod(MyOtherClass MyClass) { }
In this case, the variable "MyClass" is of type "MyOtherClass", even though you've used a name that already exists as a type name.
So when you wrote "class Signals<Signal>", you aren't referencing the existing "Signal" class. You're declaring a generic class, one that has a type parameter named "Signal" and which other than sharing the name has nothing to do with the actual "Signal" class.
Unless you actually meant to _declare_ a generic class (as opposed to simply _using_ an existing generic class or, in this case, interface), you really just want to declare your class as "class Signals" instead of "class Signals<Signal>".
I made a guess that this is in fact what you want, thus I presented that as my first suggestion. I apologize if the remainder of the discussion was just confusing the issue.
Pete
Bart - 28 Mar 2008 01:03 GMT Hi Peter,
> So when you wrote "class Signals<Signal>", you aren't referencing the > existing "Signal" class. You're declaring a generic class, one that has a > type parameter named "Signal" and which other than sharing the name has > nothing to do with the actual "Signal" class. I think you are exactly right. I didn't understand exactly what I wrote. I thought I was referencing the Signal object. Although you made me clear that this is not right I am still having some trouble to grasp the hole generic thing. The reason for this is that when I write Signals.Add(new Signal(10, "bla", bla")); I somehow think I get a reference to this Signal inside my Signals class. But I guess that's because of my Delphi background. So I have to do some more reading about this.
> I made a guess that this is in fact what you want, thus I presented that > as my first suggestion. I apologize if the remainder of the discussion > was just confusing the issue. No peter you didn't confuse me. Instead you opened my eyes. At the moment I am thinking about redesigning my classes. My Signals class is a special class that only needs to store Signals and syould be capable of validating them. So at the moment I think that Signals only need to be composed with a private List<Signal>. But I need to find out how to make iteratable so that i can write foreach(Signal s in Signal){........}.
Peter I hope that I don't give you the feeling that I that this issue doesn't have my attention because of my late responsens to your posts. But since you are so kind to put so much effort and time in it to help me, I feel obligated to you that I have have to tell that my mom had a hart atack and she in the hospital right now. Luckilly she made it and she quite allright . So that is the reason for my low response to you but as you can understand that consumes a lot of time and energy right now.
Thanks again,
Bart
Peter Duniho - 28 Mar 2008 02:42 GMT > I think you are exactly right. I didn't understand exactly what I > wrote. I [quoted text clipped - 6 lines] > "bla", bla")); I somehow think I get a reference to this Signal inside my > Signals class. I'm not sure what you mean here, as you're implying that you don't get a reference to the new Signal instance inside your Signals class. But you do. "new Signal(10, "bla", "bla")" creates (assuming that's a valid constructor) a new instance of the Signal class. The reference to that instance is passed to the Add() method. For the Add() method you've posted here, the reference is first passed to your validator, and then if it passes, it's added to the list.
At that point, the reference to the new Signal instance is now stored in the list.
> But I guess that's because of my Delphi background. So I have > to do some more reading about this. As far as I can tell, you haven't misinterpreted what that line of code does. Is there something that makes you think that you have?
> No peter you didn't confuse me. Instead you opened my eyes. At the > moment I [quoted text clipped - 6 lines] > that > i can write foreach(Signal s in Signal){........}. Well, by declaring the class as implementing IList<Signal>, you've indicated that your class will implement IEnumerable<Signal> and IEnumerable. Those in turn indicate that your class will implement the method GetEnumerator() returning an IEnumerator<Signal>.
So, to complete your implementation of IList<Signal>, one thing you'll need to do is create the method GetEnumerator(), returning an IEnumerator<Signal>. One way to do this is to write the method as an iterator. But an easier way is to just call List<Signal>.GetEnumerator(), using the List<Signal> instance in your Signals class.
This is, if I recall correctly, where this thread started. :)
> Peter I hope that I don't give you the feeling that I that this issue > doesn't have my attention because of my late responsens to your posts. > [...] You don't at all give me that feeling. I'm sorry for your personal troubles, but rest assured: it's of no concern to me how much attention you are or are not focusing on this particular question. I'm happy to answer the questions you might have as they come up, when they come up, as best as I can, if I can. It doesn't matter to me if it takes you hours, days, weeks, or longer for you to return to the question to follow up on a previous answer (though, of course, the longer you take, the greater the chance I may write something that ignores some information that was already in the thread...but as long as you don't mind that, it's not a problem).
Pete
Mel - 26 Mar 2008 19:13 GMT Changed it to public new void Add(Signal item) { }
> Another question about this. > [quoted text clipped - 19 lines] > > Bart Peter Duniho - 26 Mar 2008 23:52 GMT > Changed it to > public new void Add(Signal item) > { > } Noting that that does _NOT_ override the method. It hides it. If and when the class is used as the inherited List<Signal> class, the original Add() method will be called instead.
IMHO, it's really a poor choice to hide a method like this. The code becomes overly fragile when you do that, and it can lead to severe headaches later on.
Pete
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|