By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,742 Members | 2,026 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,742 IT Pros & Developers. It's quick & easy.

How to create multi param indexer

P: n/a
Here's a table of data I'm putting into a collection:

CodeId CodeGroup CodeSubGroup Type
1 K K.1 Shar1
2 K K.1 MD5
3 J J.2 Shar1

I want to get the data in two ways:

Codes codes;
Codegroup = "K";
codes = Collection["K"]; //returns first two rows

Codesubgroup = "K.1";
codes = Collection[Codegroup, Codesubgroup]; //returns first two rows

How do I create the type of collection and indexers for the above
syntax without creating all types of list (inside the collection) to
handle the indexers.

Any suggestions?

Thanks,
Brett

Aug 4 '06 #1
Share this Question
Share on Google+
19 Replies


P: n/a
Depends on what performance you need...

The following works fine on 2.0 and appears to meet your spec; if you need
more indexing (particularly for larger lists) then you would probably want
to look at a tree structure - but the indexer API would probably stay
broadly similar.

Marc

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

public class Code
{
public readonly int Id;
public readonly string Group, SubGroup, Type;
public Code(int id, string group, string subGroup, string type) {
Id = id;
Group = group;
SubGroup = subGroup;
Type = type;
}
}
public class CodeCollection : ICollection<Code{
private List<Code_codes = new List<Code>();
public IEnumerable<Codethis[string group, string subGroup]
{
get
{
return _codes.FindAll(delegate(Code code)
{
return string.Equals(code.Group, group) &&
string.Equals(code.SubGroup, subGroup);
});
}
}
public IEnumerable<Codethis[string group]
{
get
{
return _codes.FindAll(delegate(Code code)
{
return string.Equals(code.Group, group);
});
}
}

public void Add(Code item)
{
_codes.Add(item);
}

public void Clear()
{
_codes.Clear();
}

public bool Contains(Code item)
{
return _codes.Contains(item);
}

public void CopyTo(Code[] array, int arrayIndex)
{
_codes.CopyTo(array, arrayIndex);
}

public int Count
{
get {return _codes.Count;}
}

public bool IsReadOnly
{
get { return false; }
}

public bool Remove(Code item)
{
return _codes.Remove(item);
}

public IEnumerator<CodeGetEnumerator()
{
return _codes.GetEnumerator();
}

System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return _codes.GetEnumerator();
}
}

class Program
{
static void Main()
{
CodeCollection col = new CodeCollection();
col.Add(new Code(1, "K", "K.1", "Shar1"));
col.Add(new Code(2, "K", "K.1", "MD5"));
col.Add(new Code(3, "J", "J.2", "Shar1"));

Console.WriteLine("* K");
foreach (Code code in col["K"])
{
Console.WriteLine(code.Type);
}
Console.WriteLine("* J");
foreach (Code code in col["J"])
{
Console.WriteLine(code.Type);
}
Console.WriteLine("* K:K.1");
foreach (Code code in col["K","K.1"])
{
Console.WriteLine(code.Type);
}
}
}
Aug 4 '06 #2

P: n/a
Actually - on a stylistic note, I'm not sure I like the idea of an indexer
returning this type of entity - I would prefer these to be (overloaded)
functions, such as (to keep consistency) FindAll(string group) and
FindAll(string group, string subGroup) [otherwise unchanged]; I would expect
the indexer to accept either an index or a sensible (1:1) key, and return a
Code object.

Marc

Aug 4 '06 #3

P: n/a
I like this setup Marc. Why are you using the return this way?

get
{
return _codes.FindAll(delegate(Code code)
{
return string.Equals(code.Group, group) &&
string.Equals(code.SubGroup,
subGroup);
}
);
}

What is the difference in something like this?
get
{
_codes.FindAll(delegate(Code code)
return string.Equals(code.Group, group) &&
string.Equals(code.SubGroup,
subGroup);
}

Also, why do you need IEnumerable here:
public IEnumerable<Codethis[string group, string subGroup]

Is there a way to use the indexer syntax "this[indexOnThis]" and avoid
nulls being returned? The Dictionary<,uses a tryGetValue(, out) with
an out parameter. I prefer the indexer syntax but without the explicit
null check I must do. Although I believe you are just returning an
empty list, which would solve the problem and is nice. But in the
case that a single item is returned (some object that goes in the
list), should an empty object be returned to avoid the null? That
could cause problems for code down the road that is looking for certain
properties within that item to have values, which an empty object
won't. I guess in that case you should always have good defaults when
an object is newed up???

Thanks,
Brett

Aug 4 '06 #4

P: n/a
Also, why do you need IEnumerable here:
public IEnumerable<Codethis[string group, string subGroup]
OK; I'm returning IEnumerable<Codebecause your requirements state that a
single call to the method/indexer should return multiple rows; since I am
not using a custom-iterator, it is the same as returning the data in a list,
collection or array, but I am just hiding my implementation from the caller.
As it happens, I'm just forwarding what List<Treturns from FindAll
(another List<T>), but it can be useful to abstract this so that if I change
my inner implementation I don't have to struggle to meet an old API, nor
repair callers who are expecting e.g. a List<Tbut now getting a T[].

I can't return a "Code", as which one would I return? Typically the first,
but this doesn't meet your posted spec.
Although I believe you are just returning an
empty list, which would solve the problem and is nice. But in the
case that a single item is returned (some object that goes in the
list), should an empty object be returned to avoid the null?
OK; we need to keep clear whether we are talking about a single item or a
"list" (in the vague sense). If single, i.e. TryGetValue, then in the
absense of finding something interesting, the general behaviour is to return
default(T), which is null for classes, and zeros for value-types. In my
given code I never create a place-holder item so this is not an issue.
If talking multiple (FindAll et al) then I would expect to get a non-null,
but empty enumerator - which is what we already get.
That could cause problems for code down the road that is looking for
certain
properties within that item to have values, which an empty object
won't. I guess in that case you should always have good defaults when
an object is newed up???
Callers to TryGetValue-style methods should check the return bool and *not*
attempt to access the "out" object if it didn't report success. That is the
correct usage.
What is the difference in something like this?
get
{
_codes.FindAll(delegate(Code code)
return string.Equals(code.Group, group) &&
string.Equals(code.SubGroup,
subGroup);
}
My code both compiles and works ;-p The problem here is that you aren't
returning anything to the caller; you are calling FindAll (passing in a
predicate, which is essentially the filter condition) and then discarding
the results that it worked so hard to get. You then exit without returning
anything, which is invalid. The return that you can see is actually part of
the predicate, and NOT part of the property-getter; one of the gotchas of
anonymous methods...

Post back if that doesn't explain it enough.

Marc
Aug 4 '06 #5

P: n/a
Is there a way to create this class as a singleton but allow different
instances? I'm guessing that will work fine since the class is typed.
So,
Collection<Code>.DoSomething();
Collection<Sample>.DoSomething();
Collection<Person>.DoSomething();

Are all different collections and singletons (notice I didn't
instantiate them) but are instantiated from the same class. I didn't
have to create Code, Sample and Person collections.

By the way, the Collection<has a Fill() method which calls methods on
each object (Code, Sample, Person) to fill them from a database. This
works since the objects use an interface. The singelton will Fill()
once based on _instance being null or not. Do you see any reason why
this singleton model shouldn't work?

One other thing. I'd like singleton and non singleton versions of this
collection. The singleton versions are only meta data, which is always
read only. The data versions are read/write and I don't want them to
be singletons. However, both meta and data collections work exactly
the same. I don't want to write two classes that are identical except
for the constructor accessibility.

To start, all methods will need to be static for the singleton. In the
static methods/properties, I'll reference a private _instance object
that is the class. I'm not sure how well this will work though since
the constructor needs to be public for the non singleton instance
version. For example,

Collection<Code>.DoSomething(); //singleton - never instantiated
Collection<CodemyCodeColl = new Collection<Code>(); //non singleton
and doesn't interfer with the singleton Code version

myCodeColl.DoSomething(); //non singleton

Is there a way to make the above work?

Thanks,
Brett

Aug 5 '06 #6

P: n/a
Is there a way to create this class as a singleton but allow different
instances? I'm guessing that will work fine since the class is typed.
So,
Collection<Code>.DoSomething();
Collection<Sample>.DoSomething();
Collection<Person>.DoSomething();
You'd need to make the class generic, and the indexers might not really
be suitable for that, but in principle, yes.
One other thing. I'd like singleton and non singleton versions of this
collection.
Static = zero instances (or not specific to any one instance)
Singleton = exactly one instance

Just in terminology, it doesn't make sense to have both singleton and
non-singleton versions of the same thing; the terms are mutually
exclusive. I think what you are trying to describe is a static default
instance, while allowing additional instances, e.g. below. You could
provide static methods / accessors to the default instance, but it
would mean additional code.

// not tested for compile, but should be about right
// maybe need a static ctor to setup Default... if the initialiser
doesn't compile
public class SomeClass<T{
public readonly SomeClass<TDefault = new SomeClass<T>(); // static
(default) instance
public SomeClass() {} // does have a public ctor
}

Note here that SomeClass<Sample>.Default would be completely
independent of SomeClass<Person>.Default, which is (I think) what you
mean.

Does that help any?

Marc

Aug 5 '06 #7

P: n/a
Oops; I meant (of course):

public static readonly SomeClass<TDefault = new SomeClass<T>();

the comments gave it away, but it shows the value of testing! Heck,
it's the weekend and I'm not in the mood to fire up VS...

MGand the indexers might not really be suitable for that

The point I was trying to make here is that the Code indexer (or
FindAll, whatever) from my original example has "group" and "subgroup"
params; these obviously make no sense to a Person etc, and can't be
used in a <Tclass. One way to get around this would be to use
inheritence, and put the specialized methods into the subclasses, but
this means you have to go via the specialized class. Also note that you
would probably want to put the static instance on the subclass, to
provide access to the extended features.

Example:

public abstract class MyCollectionBase<T{} // similar to previous
code

public class CodeCollection : MyCollectionBase<Code{
public static readonly CodeCollection Default = new CodeCollection();
// again, note I prefer "FindAll" (or sommething) over
// an indexer for what this is providing ;-p
public {whatever} this[{whatever}] {...}
}

Note that the framework itself provides CollectionBase<T(or something
similar if I am being forgetful), but this doesn't provide (IIRC) the
useful Find / FindAll methods that List<Texposes, so I prefer my
approach. It also means that you can change your inner-implementation
at any time (as a non-breaking chance) without affecting your
inheritance tree (which can be a breaking change).

Marc

Aug 5 '06 #8

P: n/a
Well, before getting into some of the details, I think one major
problem is that nothing can be static. Since I'm inheriting from
ICollection<>, it doesn't allow any thing to be static.

Did I miss something about the singleton?

Thanks,
Brett

Aug 5 '06 #9

P: n/a
Ok, here it is in the very early stages but completely working. One
class that is singleton and non singleton but exclusive at runtime. I
was wondering why you chose ICollection. Notice here I didn't use it
and didn't have to implement everything it wants.

//Something to put into the collection
public class Code: ICollectionMod
{
public readonly int Id;
public readonly string Type;
private string _group, _subGroup;
public Code(int id, string group, string subGroup, string type)
{
Id = id;
Group = group;
SubGroup = subGroup;
Type = type;
}

public string Group
{
get
{
return _group;
}
set
{
_group = value;
}
}

public string SubGroup
{
get
{
return _subGroup;
}
set
{
_subGroup = value;
}
}
}

//Actual collection
public class CollectionMod < T where T: ICollectionMod
{
private static CollectionMod < T _instance = new CollectionMod < T
();
private List < T _codes = new List < T ();

public CollectionMod(){}

public List < T TryGetValue_(string group, string subGroup)
{
return _codes.FindAll(delegate(T code)
{
return string.Equals(code.Group, group) &&
string.Equals(code.SubGroup,
subGroup);
}
);
}

public static List < T TryGetValue(string group, string subGroup)
{
return _instance._codes.FindAll(delegate(T code)
{
return string.Equals(code.Group, group) &&
string.Equals(code.SubGroup,
subGroup);
}
);
}

public List < T TryGetValue_(string group)
{
return _codes.FindAll(delegate(T code)
{
return string.Equals(code.Group, group);
}
);
}

public static List < T TryGetValue(string group)
{
return _instance._codes.FindAll(delegate(T code)
{
return string.Equals(code.Group, group);
}
);
}

public void Add_(T pItem)
{
_codes.Add(pItem);
}

public static void Add(T pItem)
{
_instance._codes.Add(pItem);
}
}

//Make sure everything going into the collection has something in
common
public interface ICollectionMod
{
string Group
{
get;
set;
}

string SubGroup
{
set;
get;
}
}
//User code
static void Main(string[]args)
{
CollectionMod < Code col = new CollectionMod < Code ();
CollectionMod < Code .Add(new Code(1, "K", "K.1", "Shar1"));
CollectionMod < Code .Add(new Code(2, "K", "K.1", "MD5"));
CollectionMod < Code .Add(new Code(3, "J", "J.2", "Shar1"));
CollectionMod < Code .Add(new Code(3, "K", "K.2", "MD5"));
List < Code myStaticlist = new List < Code ();
List < Code mylist = new List < Code ();
Console.WriteLine("* K");
//Don't make me interate through these. I'll deal with them later
myStaticlist = CollectionMod < Code .TryGetValue("K");

col.Add_(new Code(1, "K", "K.1", "Test1"));
col.Add_(new Code(1, "K", "K.1", "Test2"));
mylist = col.TryGetValue_("K");
}

I had to change the indexing because this[] doesn't work for static.
I used methods on all just to be consistent. Polishing up the syntax
and I think it will be prime time.

Yes - I am duplicating methods to accomodate singleton/non singleton
versions. Keeping code to a minimum is key for this to be
maintainable, which I've done. Just not sure of a better way.

So I guess my question at this point is - why not use such a class?

Brett

Aug 5 '06 #10

P: n/a
One class that is singleton and non singleton but exclusive at runtime.
public CollectionMod(){}
Nope; since it has a public ctor, I can create as many instances of it
as I like. Ergo, not a singleton. A singleton is something that *can
only* (and I really, really, mean *only*) have *one* instance. This
typically means the ctor is private, and a single instance is exposed
via a static property. What you have is a collection with a static
instance. OK, the difference is largely terminology, but I think it is
important to get this right, as they are terms with specific, agreed,
meanings.
Since I'm inheriting from ICollection<>, it doesn't allow any thing to be static.
No, you are /implementing/ ICollection<>, which is different. Either
way, it has no effect /whatsoever/ on your ability to add static
members.
I was wondering why you chose ICollection. Notice here I didn't use it
and didn't have to implement everything it wants.
Yes, ICollection<Tplaces a few demands, but it also allows for a lot
of flexibility downstream. If you don't need this flexibility, don't
use it... but at least implement IEnumerable<T>, if only for good
manners ;-p This allows access to e.g. foreach. In production code, I
would be suprised to find something named with Collection that doesn't
implement ICollection<T(or ICollection)
public List < T TryGetValue_(string group, string subGroup)
Personally I find this very confusing as a signature. It isn't the
standard pattern for this, but if it works for you... whatever.
public void Add_(T pItem)
public static void Add(T pItem)
You've hit a snag here; these _ methods aren't very tidy, but again, it
doesn't hurt anyone... Again, you wouldn't need this with a static
default implementation, as the static instance would share a codebase
with the standard instances; code re-use. This is more noticeable when
providing a full collection implementation, which (as you noted) you
aren't doing.
So I guess my question at this point is - why not use such a class?
Nobody will stop you. It just isn't quite as elegant as it perhaps
could be, but sometimes that is life. The ICollectionMod, for instance,
seems so specific that it could only /possibly/ be of use with the Code
class, so why bother with the generics? Then there's the code
duplication for statics. Again, if you are happy then I am happy... ish
;-p

Good luck; I'm still here if you havef more questions / observations...

Marc

Aug 6 '06 #11

P: n/a
The ICollectionMod, for instance, seems so specific that
it could only /possibly/ be of use with the Code
class, so why bother with the generics?
Sorry - maybe a bit premature here; I can see how a 2-level collection
could be used in multiple scenarios. Perhaps the problem here is
insisting on the value implenting an interface. If you perhaps made
this part of the key when adding the items (mirroring the Dictionary<T>
interface) this would be quite versatile, while demanding /nothing/ of
the value items? Incomplete example follows - not tested, but principle
is sound:

public class TwoTierCollection<TOuterKey, TInnerKey, TValue{
public class TwoTierItem {
public readonly TOuterKey OuterKey;
public readonly TInnerKey InnerKey;
public readonly TValue Value;
internal TwoTierItem(... outer, inner, value... ) {
//assign values
}
}
private readonly List<TwoTierItem<TOuterKey, TInnerKey, TValue>>
_data = new ...
pubic void Add(TOuterKey outerKey, TInnerKey innerKey, TValue value)
{
_data.Add(new TwoTierItem(outerKey, innerKey, value);
}
public IEnumerable<TValueFindAll(TOuterKey outerKey) {
//... call FindAll, probably using
EqualityComparer<TOuterKey>.Default.Equals(blah)
}
public IEnumerable<TValueFindAll(TOuterKey outerKey, TInnerKey
innerKey) {
//... call FindAll, probably using
EqualityComparer<TOuterKey>.Default.Equals(blah)
// and EqualityComparer<TInnerKey>.Default.Equals(blah)
}
}

This would allow all sorts of combinations, without any faffing with
the value-item having to implenent some interface... i.e.

TwoTierCollection<string, string, Code// for your example
TwoTierCollection<int, bool, MyClass// for something else...

You could also add a default static instance on there if it helped
you... although it might be more appropriate to add this to the
instances where it applies, i.e.

public class Code {
public readonly static TwoTierCollection<string, string, Code>
MasterList = ... // blah
// whatever else
}

Marc

Aug 6 '06 #12

P: n/a
The collectionMod will take anything that implements the ICollectionMod
interface, not just Code types. But having everything implement the
interface can be a big issue. The interface can never change
thereafter, not even considering any retro fitting.

You are correct in that ICollectionMod isn't technically a singleton
because of the constructor access. However, you can use it as a
singleton with no problems. Or you can instantiate and put that into a
reference type.

//non singleton version
CollectionMod<CodecodeCol = new CollectionMod<Code>( );
//singleton version
CollectionMod<Code>.Add( new Code( 1, "K", "K.1", "Shar1" )
);

I was incorrect to say ICollection was preventing me from using the
indexers as static. The problem was you can't do
static this[]{}

since this isn't static. Is there a way to have a static indexer?

I like the last example but do you mean for TwoTierItem to be a
generic?

You do this but the class isn't generic:
private readonly List<TwoTierItem<TOuterKey, TInnerKey, TValue>>

I see your point about using ICollection for foreach loops. But is
there a way to get that and also have something that does give the
results back into a list. So its a restricted collection from a
collection. Although it seems a little strange to get a collection
from a collection or more specifically a list from a list. I suppose a
method of some type would be the way to go. Maybe it isn't so strange
if some interface is already doing this. It just may be the case that
I don't want to immediately foreach through my results.
Thanks,
Brett

Aug 7 '06 #13

P: n/a
It just may be the case that I don't want to
immediately foreach through my results.
That is reasonable enough, and certainly a List<Twoluld allow more
interesting queries; it still doesn't meet the "normal" TryGetValue
configuration, though, and I'm not sure that a 1:many (keys:values)
collection can ever really offer this. "Find", "GetByKeys" etc all
would be more instructive names. Again, if TryGetValue works for you,
it would suffice...
Is there a way to have a static indexer?
No
However, you can use it as a
singleton with no problems.
Sorry to be a pedant; static instance: /not/ singletion ;-p
I like the last example but do you mean for TwoTierItem to be a
generic?
I meant for it to be a nested class of a generic, so my code was wrong
and confusing; here is a better example (i.e. it compiles):

public class TwoTierCollection<TOuterKey, TInnerKey, TValue>
{
public class TwoTierItem
{
private TOuterKey _outerKey;
private TInnerKey _innerKey;
private TValue _value;
public TOuterKey OuterKey { get { return _outerKey; } }
public TInnerKey InnerKey { get { return _innerKey; } }
public TValue Value { get { return _value; } }
public TwoTierItem(TOuterKey outerKey, TInnerKey innerKey,
TValue value)
{
_outerKey = outerKey;
_innerKey = innerKey;
_value = value;
}

}
private readonly List<TwoTierItem_data = new
List<TwoTierItem>();
public void Add(TOuterKey outerKey, TInnerKey innerKey, TValue
value)
{
_data.Add(new TwoTierItem(outerKey, innerKey, value));
}
public List<TwoTierItemFindAll(TOuterKey outerKey)
{
IEqualityComparer<TOuterKeyouterComparer =
EqualityComparer<TOuterKey>.Default;
return _data.FindAll(delegate(TwoTierItem item)
{
return outerComparer.Equals(outerKey, item.OuterKey);
});
}

}

Marc

Aug 7 '06 #14

P: n/a
Thanks again on the example.
>>Sorry to be a pedant; static instance: /not/ singletion ;-p
How does the singleton work then for a generic type. If I have a
generic collection and reference three types:

Coll<Code>.Add()
Coll<Sample>.Add()
Coll<MyClass>.Add()

does this provide independent List<within each collection? Meaning,
they are using their own static instances and not one (singleton).

Thanks,
Brett

Aug 7 '06 #15

P: n/a
By the way, can't you compromise with ICollection by just having a
public property that exposes the List<>? In those cases you need to
foreach or what ever it may be, those things will be available.

In the end, TryGetValue() will work the same. I agree it is better.
It will return a bool and use a out ref.

Thanks,
Brett

Aug 7 '06 #16

P: n/a
How does the singleton work then for a generic type. If I have a
generic collection and reference three types:
Coll<Code>.Add()
Coll<Sample>.Add()
Coll<MyClass>.Add()
does this provide independent List<within each collection?
If Coll<Tdeclares a static List<T>, then yes you will get an independent
List<Tfor every choice of T you throw at the generic class.
Meaning, they are using their own static instances and not one
(singleton).
Well, strinctly Coll<ClassAand Coll<ClassBare different type-defs; you
can verify this by checking the typeof()s; they are not the same - a new
type-def ("Type" instance) is created (by the runtime, not the compiler) for
every permutation of template parameters to a generic (although the JIT can
be re-used for reference-type permutations). Under this guise (and assuming
the standard singleton definition is met), you could happily say that
Coll<Thas a singleton for any choice of T. If you wanted all the Coll<T>
classes to share something common, then they would have to e.g. reference a
static member of a non-generic type.

Marc
Aug 7 '06 #17

P: n/a
By the way, can't you compromise with ICollection by just having a
public property that exposes the List<>?
Well... yes; but you are really exposing your implementation, which destroys
a lot of the advantages of encapsulation; for instance, I could have this
Add method (not from the same example):

public void Add(string key, SomeClass value) {
if(value==null) throw new ArgumentNullException("value");
if(key==null) throw new ArgumentNullException("key");
if(!value.IsValid) throw new ArgumentException("value", "Only valid
SomeClass instances can be used");
if(value.Parent != null) throw new ArgumentException("value", "The
SomeClass instance is already owned");
if(key.StartsWith("b")) throw new ArgumentException("key", "Sorry, I am
not an apiarist");
// validation passed; allow the item in
_data.Add(key, value); // assumes a dictionary or similar, since has a key
param
}

If the inner-container object is directly exposed, then it allows callers to
bypass all of your validation efforts, and just call:

MyCollection.InnerList.Add("bHaHaHaHaHa", null);
In those cases you need to foreach or what ever it may be, those things
will be available.
Again... "Well... yes", but in most cases you can keep an encapsulated model
and expose these through forwarding with no real effort. You can also
improve on things; for instance, in the example from previous, the List
enumarator would expose TwoTierItem instances; not necessarily what you
want - however, you can easily do things like:

IEnumerator<TValueValues {
get {
foreach (TwoTierItem item in _data) {
yield return item.Value;
}
}
}

We can now enumerate on the values (only) without having to worry about
TwoTierItems getting in the way - but I had to add this code... (actually,
better implementations of this pattern are possible - that keep in-sync with
the data, but it is more code).

Again - if what you have works for you, then all well and good. I'm being a
bit purist here to highlight some points that might bite you later on... but
by all means be the pragmatist and pick the points that work for your needs,
and disregard the rest...

Marc
Aug 7 '06 #18

P: n/a
What am I doing wrong for the multi indexer?

public List < TwoTierItem FindAll(TOuterKey outerKey, TInnerKey
innerKey)
{
IEqualityComparer < TOuterKey outerComparer = EqualityComparer <
TOuterKey
.Default;
IEqualityComparer < TInnerKey innerComparer = EqualityComparer <
TInnerKey
.Default;
return _data.FindAll(delegate(TwoTierItem item)
{
return outerComparer.Equals(outerKey, item.OuterKey);
{
return innerComparer.Equals(innerKey, item.InnerKey);
}
}
);
}

I first check the outter key, which gives the bigger set. Then I
restrict that set on the inner key, giving the final (smaller) set.

Thanks,
Brett

Aug 7 '06 #19

P: n/a
Spoke to soon. Here's the correction:

public List < TValue FindAll(TOuterKey outerKey, TInnerKey innerKey)
{
List < TValue resultList = new List < TValue ();

IEqualityComparer < TOuterKey outerComparer = EqualityComparer <
TOuterKey
.Default;
IEqualityComparer < TInnerKey innerComparer = EqualityComparer <
TInnerKey
.Default;
List < TwoTierItem resultListPrime =
_data.FindAll(delegate(TwoTierItem
item)
{
return outerComparer.Equals(outerKey, item.OuterKey) &&
innerComparer.Equals(innerKey, item.InnerKey);
}
);

foreach (TwoTierItem item in resultListPrime)
{
resultList.Add(item.Value);
}

return resultList;
}

This version also gives back the thing you put in, which seems more
natural.

Brett

Aug 7 '06 #20

This discussion thread is closed

Replies have been disabled for this discussion.