NSaid
NSaid

Reputation: 751

Generalize a function

I am trying to figure out if there is a way to generalize a function that takes a Hashset of two unrelated objects with similar attributes. I have some sample code below:

private IList<IDictionary<string, string>> BuildDictionary(HashSet<ClassA> ClassA)
{
    IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
    foreach (var a in ClassA)
    {
        Dictionary<string, string> aDictionary = new Dictionary<string, string>();
        aDictionary.Add(a.Code, a.Code + "," + a.Name);
        data.Add(aDictionary);
    }

    return data;
}

private IList<IDictionary<string, string>> BuildDictionary(HashSet<ClassB> ClassB)
{
    IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
    foreach (var b in ClassB)
    {
        Dictionary<string, string> bDictionary = new Dictionary<string, string>();
        bDictionary.Add(b.Code, b.Code + "," + b.Name);
        data.Add(bDictionary);
    }

    return data;
}

Thus as evident from the code, the two classes are not related but they both are in a HashSet and contain similar attributes (code, name). I have tried using the generic T but that failed due to the fact that I don't have the generic class T created. Would there be anyway to get around this issue without creating a new class?

Upvotes: 0

Views: 229

Answers (2)

meklarian
meklarian

Reputation: 6625

If your source classes are sealed or can't be modified to a common interface, you can use accessors for the parts that are needed, as one might do in most LINQ queries.

Here's an example implementation. Note that toKey() and toMemberValue() could be named more appropriately, but this is enough to replicate what you are doing for any class where you can specify a lambda to retrieve the relevant property, and isn't dependent upon the class necessarily having the same property names so long as the lambda is written accordingly. Main() shows what it would look like to use this method for both cases.

public IList<IDictionary<string, string>> BuildDictionary<T>(HashSet<T> sourceSet, Func<T, string> toKey, Func<T, string> toMemberValue)
{
  IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();

  foreach (var element in sourceSet)
  {
    Dictionary<string, string> newLookup = new Dictionary<string, string>();
    newLookup.Add(toKey(element), $"{toKey(element)},{toMemberValue(element)}");
    data.Add(newLookup);
  }

  return data;
}

void Main()
{
  HashSet<ClassA> setOfAs = new HashSet<ClassA>(new[] { new ClassA { Code = "foo", Name = "bar" }, new ClassA { Code = "foo2", Name = "bar2" } });
  HashSet<ClassB> setOfBs = new HashSet<ClassB>(new[] { new ClassB { Code = "foo", Name = "bar" }, new ClassB { Code = "foo2", Name = "bar2" } });

  var lookupOfAs = BuildDictionary(setOfAs, x => x.Code, x => x.Name);
  var lookupOfBs = BuildDictionary(setOfBs, x => x.Code, x => x.Name);
}

// Define other methods and classes here
public class ClassA
{
  public string Code { get; set; }
  public string Name { get; set; }
}

public class ClassB
{
  public string Code { get; set; }
  public string Name { get; set; }
}

Upvotes: 3

Igor
Igor

Reputation: 62238

If you own the source code to both types you can implement a common interface.

private IList<IDictionary<string, string>> BuildDictionary<T>(HashSet<T> someHashSetOfTs) where T : ICommon
{
    IList<IDictionary<string, string>> data = new List<IDictionary<string, string>>();
    foreach (var a in someHashSetOfTs)
    {
        Dictionary<string, string> aDictionary = new Dictionary<string, string>();
        aDictionary.Add(a.Code, a.Code + "," + a.Name);
        data.Add(aDictionary);
    }

    return data;
}

Interface definition

public interface ICommon {
   string Code {get; }
   string Name {get; }
}

And now apply ICommon to both types ClassA and ClassB.

Upvotes: 3

Related Questions