Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get values from var-source with linq

Tags:

c#

var

linq

I have a Dictionary:

Dictionary<int, Type> AllDrillTypes = new Dictionary<int, Type>()
{
  {13,typeof(TCHEMISTRY)},
  {14,typeof(TDRILLSPAN)}
};

where TCHEMISTRY and TDRILLSPAN are classes. Then I want to get rows from one of this classes like this:

Type T = AllDrillTypes[13];
var LC = Activator.CreateInstance( typeof(List<>).MakeGenericType( T ) );
MethodInfo M = T.GetMethod("FindAll", BindingFlags.Public | BindingFlags.Static, null, new Type[] { }, null);    
LC = M.Invoke(null, new object[] { });

All this code works correctly. After that I need to get some rows like this:

var LingLC = from obj in LC where obj.RunID == 1001 select obj;

But this line causes error:

"Could not find an implementation of the query pattern for source type 'object'. 'Where' not found."

What's wrong with this code line?

like image 903
Serg Okunev Avatar asked Oct 06 '22 07:10

Serg Okunev


2 Answers

Even if you can't change the class definitions, you can avoid using reflection:

// Getter dictionary rather than type dictionary.
Dictionary<int, Func<IEnumerable<object>>> DrillTypeGetters =
    new Dictionary<int, Func<IEnumerable<object>>>()   
    {  
        { 13, () => TCHEMISTRY.FindAll().Cast<object>() },
        { 14, () => TDRILLSPAN.FindAll().Cast<object>() }
    };
Dictionary<int, Func<object, int>> IDGetters =
    new Dictionary<int, Func<object, int>>()
    {
        { 13, o => ((TCHEMISTRY)o).RunID },
        { 14, o => ((TDRILLSPAN)o).RunID }
    };

IEnumerable<object> LC = DrillTypeGetters[13]();
IEnumerable<object> LingLC = 
    from obj in LC
    where IDGetters[13](obj) == 1001
    select obj;

Or you could even just switch on 13/14 and run a completely different method per type.

if (choice == 13)
    IEnumerable<TCHEMISTRY> LingLC =
        TCHEMISTRY.FindAll().Where(tc => tc.RunID == 1001);
else if (choice == 14)
    IEnumerable<TDRILLSPAN> LingLC =
        TDRILLSPAN.FindAll().Where(td => td.RunID == 1001);

Basically, if the two classes don't share any common hierarchy, you can't write any common code to deal with them. If they have lots of similar properties, you can use getters as in my first example to provide a way to get the similar properties whatever type of class you're dealing with. If they don't even have similar properties, don't try to write shared code.

like image 86
Rawling Avatar answered Oct 10 '22 02:10

Rawling


Maybe you could rewrite your code to something like this, .... to get a more type-safe solution (without using reflection).

void Main()
{
    var driller1 = new DrillerWhichYouCannotChange1();
    var driller2 = new DrillerWhichYouCannotChange2();

    var allDrillTypes = new Dictionary<int, IList<IDriller>>()
    {
        { 13, new List<IDriller>() { new DrillerWhichYouCannotChange1Adapter(driller1) } },
        { 14, new List<IDriller>() { new DrillerWhichYouCannotChange2Adapter(driller2) } },
    };

    Console.WriteLine(allDrillTypes[13][0].SomeCommonProperty); // prints 123
    Console.WriteLine(allDrillTypes[14][0].SomeCommonProperty); // prints 456
}

interface IDriller
{
    int SomeCommonProperty { get; }
}

class DrillerWhichYouCannotChange1Adapter : IDriller
{
    private DrillerWhichYouCannotChange1 inner;

    public DrillerWhichYouCannotChange1Adapter(DrillerWhichYouCannotChange1 inner)
    {
        this.inner = inner;
    }

    public int SomeCommonProperty { get { return this.inner.PropertyX; } }
}

class DrillerWhichYouCannotChange2Adapter : IDriller
{
    private DrillerWhichYouCannotChange2 inner;

    public DrillerWhichYouCannotChange2Adapter(DrillerWhichYouCannotChange2 inner)
    {
        this.inner = inner;
    }

    public int SomeCommonProperty { get { return this.inner.PropertyY; } }
}

class DrillerWhichYouCannotChange1
{
    public int PropertyX { get { return 123; } }
}

class DrillerWhichYouCannotChange2
{
    public int PropertyY { get { return 456; } }
}

EDIT: If you cannot change the driller classes, you could use the adapter-pattern to create one adapter per driller, which implements IDiller.

like image 20
ulrichb Avatar answered Oct 10 '22 04:10

ulrichb