I'm creating a list of my defined objects like so
List<clock> cclocks = new List<clocks>();
for each object in the list i'm calling a method moveTime, like so
foreach(clock c in cclocks)
{
c.moveTime();
}
is the a way i can write some cleaver thing so i can call
cclocks.moveTime();
it would then go though the list doing that method
I guess I want to create a collection method?
I'm guessing there must be some thing I can do I just don't know what.
thanks for your help
You could write an extension method on List<T> which iterates this and calls moveTime() on each of the items in the collection. See this article for more information.
This approach obscures a lot of information, though. If I we're you, I'd go with the for-loop. And if you're just calling one method on each of the objects, you can shorten the for-loop, like so:
// no need to declare scope if you're just doing one operation on the collection
foreach(var object in collection) object.method();
... Or use LINQ:
collection.ForEach(object => object.method());
I'm not quite sure but perhaps you are talking about ForEach() method of List<T>
cclocks.ForEach(c => c.MoveTime());
You could write an extension method to do this.
http://msdn.microsoft.com/en-us/library/bb383977.aspx
You can either create a class that inherits from
List<clock>
or create an extension method for List<clock>
Another solution is to derive new class from List<Clock> and then add all the methods you need. Something like this:
public class ClocksList : List<Clock>
{
public void MoveSingleClock(Clock clock)
{
clock.MoveTime();
}
public void MoveAllClocks()
{
foreach(clock c in InnerList)
{
MoveSingleClock(c);
}
}
}
You can use new class like this:
ClocksList clocks = new ClocksList();
// Fill the list
clocks.Add(new Clock());
...
// Move time on all clocks
clocks.MoveAllClocks();
// Move single clock
Clock c = new Clock();
clocks.Add(c);
clocks.MoveSingleClock(c);
Related
I'm using C# and I don't know if it's possible invoke a method for all the object in a list in the same moment, without loop like for or foreach.
Ex.
class Person
{
public void doSomething()
{
//
}
}
List<Person> _personlist = new List<Person>();
_personlist(SelectAll.doSomething()); //something like this
//invoke the same method at the same time for all the object in the list
I think that Linq allow this, but at the moment I don't find anything.
You have to iterate the List, either way.
LINQ is not really useful for producing side effects, it is for querying collections. You can call your method with LINQ, but it will do the iteration (internally).
So it is better that you use an explicit loop construct to convey the code intention clearly.
With LINQ if your object has a instant method than you can do:
var something = yourList.Select(r=> r.MethodToCall()).ToList();
But don't do the above...
If you want to write a query that can operate in parallel check out plinq.
var _personlist = new List<Person>();
_personlist.AsParallel().ForAll(i=>i.DoSomething());
LINQ does offer a ForEach extension method that can give you a one liner option. It's technically still a loop though....
This is an example I've used before...
List<StreamWriter> Writers;
...
Writers.ForEach(x => x.Write(...));
On the List object you can call the extension method ForEach.
IEnumerable<int> numbers = new List<int>() { 1, 2, 3 };
numbers.ForEach(x => Console.WriteLine(x));
Let's say I have a method that calls another method with some parameters, something like this:
public void SomeMethod()
{
List<SomeObject> TheList = SomeQueryThatReturnsTheList();
TheList = DoSomeWorkWithList(TheList);
}
public List<SomeObject> WorkForList(List<SomeObject> TheListAsParameter)
{
foreach (SomeObject x in TheListAsParameter)
{
....
}
return TheListAsParameter;
}
As you can see, the method WorkForList returns the list it received. My question is this: if I don't return the list and rewrite the signature as public void WorkForList(List<SomeObject> TheListAsParameter) is pass by reference in c# going to mean that TheList in SomeMethod is going to be updated with the work that's done in the WorkForList method? If so, will the following code work the same:
public void SomeMethod()
{
List<SomeObject> TheList = SomeQueryThatReturnsTheList();
DoSomeWorkWithList(TheList);
}
public void WorkForList(List<SomeObject> TheListAsParameter)
{
....
}
Thanks.
Well if you don't use the ref keyword, its address will be passed by value, meaning you will be able to change its element, but you can't initialized it or can't assign it null. for example. If in your method you do:
public void WorkForList(List<SomeObject> TheListAsParameter)
{
TheListAsParameter = null;
}
You will not see the difference in the caller.
You should see this article: Parameter passing in C# by Jon Skeet
In this case, the code will do what you want to do, BUT bear in mind two things:
C# is "pass by value" language. It passes the address of the object, so this will only work if you work with this instance, not change the instance itself. For that, you should use ref keyword, but that usually ends up with harder to read code.
returning objects vastly improves readability - what you do is considered a side-effect, a user of your method (another team member maybe) may not be aware you are modifying the list contents.
Yes, you can do that. But returning the object might be useful, for clarity, and to allow methods chaining.
For example with your first WorkForList method :
yourObject.WorkForList(list).DoSomethingWithTheReturnedList();
Yes - this should behave exactly as you've described... Surely you can just test the code you've already written?
Yes, as long as your WorkForList() method doesn't have a line like this:
TheListAsParameter = something;
then any changes you make to TheListAsParameter will be reflected in the calling method without returning it.
To speak precisely here, in this case you aren't passing a variable by reference. You are passing a reference type by value. Pass by reference involves the use of the ref keyword in C#.
As long as you don't use foreach to modify values of the list:
foreach (SomeObject x in TheListAsParameter)
{
....
}
As you are not allowed to modify the contents of a Collection you are walking through using foreach.
I wanted to do something like co-variance in C# but I dont have here any inheritance .
I have this code :
public interface IBirthday
{
void Dance ();
}
public class Birthday:IBirthday
{
public void Dance()
{}
}
void Main()
{
List<Birthday> l= new List<Birthday>();
List<IBirthday> d = l; //<--- How can I accomplish that ?
}
HOw can I make this work ? (besides iterating and build manually ( linq or loop))
List<IBirthday> d = list of birthdays ?
does iterating/linq is the only choice?
It's not possible to assign a List<Birthday> to a List<IBirthday> without creating a brand new list (it can be hidden from you, but it must happen somewhere).
If what you were trying to do were possible then what would happen when someone did:
public class UnBirthday : IBirthday { ... }
d.Add(new UnBirthday());
Well, it's a List<IBirthday>, so it thinks that it's able to add the new item. But the underlying list is actually a List<Birthday>, and you can't add an UnBirthday to that list. Given the choice between allowing this and just crashing at runtime, C# made the decision (correctly, in my opinion) of just not allowing it in the first place.
The only way to utilize generic argument covariance, which is what you're trying to do, is to assign it to something that can only read information out, and never put information in. One example of this is IEnumerable<T>. Every single Birthday is an IBirthday, and there's no way for IEnumerable to be given an IBirthday that's not a Birthday, so saying:
List<Birthday> l= new List<Birthday>();
IEnumerable<IBirthday> d = l;
works just fine.
You can use:
d = l.Cast<IBirthday>.ToList();
Hi I have a Method like this:
public T LoadR<T, K>()
where T : ObservableCollection<K>, new()
where K : IStoreElement, new() {
T onC = new T();
//....
return (onC);
}
Further I have a class XObservableCollection which derivies from ObservableCollection.
It works as it is when I call:
Categories = LoadR<ObservableCollection<Category>,Category>();
Products = LoadR<XObservableCollection<Product>,Product>();
What I want to do is to make a call like this (avoid passing the K as extra parameter):
Categories = LoadR<ObservableCollection<Category>>();
Products = LoadR<XObservableCollection<Product>>();
I know that I could write an extension for it.
But I curious if there is a way to achive this without it.
Manfred
I don't think you can.
C# has a mechanism to understand generic agruments from method paramaters when used in it, but not from other generic arguments of the same method. It doesn't work.
Maybe you can change your signature to:
private static ObservableCollection<K> LoadR<K>(.ObservableCollection<K> onC)
where K : IStoreElement, new()
{
//....
return onC;
}
Usage would be:
static void TestLoad()
{
var result1 = LoadR(new ObservableCollection<Something>());
var result2 = LoadR(new DerivedClassFromObservableCollection<Something>());
}
Which I agree is not that good, and I can se it's not what you are looking for.
But just because C# wouldn't let you try to infer the types from the generic arguments.
.....
The other way aroudn is to make it use a specific collection. I can see you don't want this even more.
So, one thing you can do is make it return IEnumerable instead, then you usage will be something like:
static void TestLoad()
{
var result1 = new ObservableCollection( LoadR<Something>() );
var result1 = new DerivedClassFromObservableCollection( LoadR<Something>() );
}
Which may not be good also if you want to do fancy things with the collection itself, because you no-longer own it.
....
I would go for the very first option myself.
I have a custom list which inherits from Generic.List<T> like this:
public class TransferFileList<T> : List<TransferFile> { .. }
When I set (where 'Files' is a TransferFileList<T>):
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
the 'files' object resolves as System.Collections.Generic.List<TransferFile>, not TransferFileList<T>, which is what I would expect as it was what was being filtered through the Where, so how could I successfully return a list of TransferFileList<T> into 'files'?
I did try:
var files = uploadResponse.Files.Where(x => !x.Success).ToList()
as TransferFileList<TransferFile>;
but using that safe cast, it just resolves as null.
Thanks guys and gals.
First, I have to ask why you are inheriting from List<T>? 99% of the time that's a bad idea.
If you want to extend the functionality of a list, use extension methods:
public static something PrintErrors(this List<TransferFile> list)
{
//do your printing logic
}
On to the answer: ToList() operates on an IEnumerable<T> and converts the members of the sequence to a List of the same type. Since you inherit from List<T> which implements IEnumerable<T>, that's what happens there.
Where() works the same way - operates on an IEnumerable<T> and returns an IEnumerable<T>.
To get some arbitrary list-like object back, like you have, you need to add the items in a sequence to your custom list, like so:
var myFiles = new TransferFileList<TransferFile>();
myFiles.AddRange(originalFileList.Where(condition));
You can add an extension method for IEnumerable<TransferFile> to handle that scenario:
public static TransferFileList ToTransferFileList(
this IEnumerable<TransferFile> files)
{
return new TransferFileList(files);
}
// ...
var files = uploadResponse.Files.Where(x => !x.Success).ToTransferFileList();
This provides you with the TransferFileList instead of just a List<TransferFile>. Note the reason your as returns null is because while TransferFileList is a List<TransferFile>, the same does not hold in the other direction. That is, your List<TransferFile> is NOT a TransferFileList object.
I agree with #RexM that any attempt at subclassing List<T> be avoided due to the multitude of pitfalls associated. I suggest Composition (Has-A rather than Is-A) or sticking with the base class library collections instead.
Thanks guys.
I like SLV's extension approach, but is there any other straight casting approach?
If not I might just go with the reverted in-line approach I was hoping to avoid:
var transferFiles = new TransferFileList<TransferFile>();
if (files != null)
transferFiles.AddRange(files);