Reputation: 4125
In my application there is a List<MyItem>
with a getter only:
public List<MyItem> myList
{
get
{
MyHost.GetItemFromID(_i1); //this may be a long operation
MyHost.GetItemFromID(_i2);
MyHost.GetItemFromID(_i3);
MyHost.GetItemFromID(_i4);
MyHost.GetItemFromID(_i5);
}
}
This list needs sometimes to be retrieved as whole and other times only certain item has to be accessed: i.e. myList[3]
. Is there a way of not building the entire list as I only need the fourth item?
Upvotes: 0
Views: 675
Reputation: 73253
Build a map in advance and return only items you wish to.
List<int> map = new List<int>
{
_i1,
_i2,
_i3,
_i4,
_i5,
};
public IEnumerable<MyItem> myList(params int[] indices)
{
if (!indices.Any())
return map.Select(MyHost.GetItemFromID);
return indices.Select(i => MyHost.GetItemFromID(map[i]));
}
// so you call
myList(); // for all items; decide on this API, may be separate to two methods?
myList(0); // or
myList(4); // or
myList(1, 3); // all loaded only on demand
Use a dictionary if you want more control over indexing. Ideally, for some reason this looks like you should be passing all IDs to DB in one go and SQL directly handle it, if that is the case.
Upvotes: 1
Reputation: 460238
You could return IEnumerable<MyItem>
and use yield return
:
public IEnumerable<MyItem> MyItems
{
get
{
yield return MyHost.GetItemFromID(_i1); //this may be a long operation
yield return MyHost.GetItemFromID(_i2);
yield return MyHost.GetItemFromID(_i3);
yield return MyHost.GetItemFromID(_i4);
yield return MyHost.GetItemFromID(_i5);
}
}
Then it is using deferred execution and you can write:
var fourItems = MyItems.Take(4).ToList();
Note that it might be a good idea to change the order of execution if the order doesn't matter and only the first call of GetItemFromID
takes more time than the others:
yield return MyHost.GetItemFromID(_i2);
yield return MyHost.GetItemFromID(_i3);
yield return MyHost.GetItemFromID(_i4);
yield return MyHost.GetItemFromID(_i5);
yield return MyHost.GetItemFromID(_i1); //this may be a long operation
I think i have misuderstood the requirement. I've read "sometimes I only need the fourth item" as "only need four items"
So you could use my aproach but with ElementAt
:
MyItem fourthItem = MyItems.ElementAt(3);
If you don't know if there's a fourth use ElementAtOrdefault
.
Upvotes: 3
Reputation: 109762
I don't know what type your keys for _i1
etc are, but let's assume they are ints. Then you could do this:
public IEnumerable<MyItem> GetItems(params int[] keys)
{
return keys.Select(key => MyHost.GetItemFromID(key));
}
Which you could call like this:
var myItems = GetItems(_i2, _i3, _i5).ToList();
or
var myItems = GetItems(_i3).ToArray();
and so on.
Note: If you only ever want a list returned, you can do the conversion inside GetItems()
itself:
public List<MyItem> GetItems(params int[] keys)
{
return keys.Select(key => MyHost.GetItemFromID(key)).ToList();
}
This approach requires a method rather than a property, though.
Upvotes: 1
Reputation: 1324
You could wrap the list with a class, say 'myListContainer' and overload its '[]' operator so that you could do something like this:
myListContainer[3]
which will invoke the call
MyHost.GetItemFromID(_i3);
and return the desired list item.
I'll add a full example if needed
EDIT
public class myListContainer
{
public MyItem this[int i]
{
get
{
return MyHost.GetItemFromID(i);
}
}
}
and add method to get the entire list.
Upvotes: 5