views:

218

answers:

5

I have this function:

Program A

public ICollection<ReportLocationInfo> GetAllReportsInstalled() 
{
    return _Reports;
}

I am calling it through reflection dynamically:

Program B

internal ICollection<Object> Scan(string path)
{
     MethodInfo GetReports =
          _reportFactoryType.GetMethod("GetAllReportsInstalled");

     return (List<Object>)GetReports.Invoke(_reportFactory, null);
}

I am casting to List because I don't have ReportLocationInfo at Program B, and I have my own translation function in hand. This of course doesn't work.

Any suggestions?

A: 

You won't be able to cast to the class that you haven't define in current assembly or the assemblies that the current assembly is referencing. There is just no way to workaround it; static typing is there for this reason.

You said that you want it to translate dynamically, by this I assume that you want it to be able to get the Intellisense out even though the class is not defined yet, well, that's just not possible.

Ngu Soon Hui
I know, that is why i want to translate it dynamically on my side. Is that possible? How?
Feel
A: 
Activator.CreateInstance(typeof(List<>).MakeGenericType(yourtype)) as IList

I am not sure what you are trying is correct. How can ReportInfo suddenly change to ReporttLocationInfo?

leppie
You are correct, my mistake. I edited that out. I want to ReportLocationInfo into Object because ReportLocationInfo does not exist in ProgramB. Can that be done?
Feel
A: 

First of all, you really don't want to do this.

If you insist, you will have to inspect the return value of your GetReports.Invoke call through reflection as well. Start with:

Object reports = GetReports.Invoke(_reportFactory, null);

Work from there, knowing that reports is actually of type ICollection<ReportLocationInfo>

jeroenh
+2  A: 

ICollection<T> implements System.Collections.IEnumerable. You can cast to this interface and then use a foreach to iterate through your objects.

MethodInfo GetReports = _reportFactoryType.GetMethod("GetAllReportsInstalled");
IEnumerable reports = (IEnumerable)GetReports.Invoke(_reportFactory, null);

foreach (object report in reports)
{
    // Use reflection to read properties or add to a new List<object> if you
    // need an ICollection<object>
}
ybo
A: 

A simple way would be:

private ICollection<object> ScanInternal(string path)
{
     List<object> result = new List<object>();

     MethodInfo GetReports = 
           _reportFactoryType.GetMethod("GetAllReportsInstalled");

     IEnumerable reports = GetReports.Invoke(_reportFactory, null)
           as IEnumerable;

     if (reports != null)  // or exception if null ?
     {
         foreach (object report in reports)
             result.Add(report);
     }

     return result;
}

But a more appropriate way would be to create an interface in a separate shared assembly (e.g. IReportLocationInfo), and then use this interface in both assemblies.

Consider refactoring your code a bit to achieve this, because invoking methods using Reflection on an object instance is almost like doing plain C. You get no type safety.

So, the OOP way would be to have all interfaces in a separate assembly (referenced by both program A and program B):

public interface IReportFactory
{
     IEnumerable<IReportLocationInfo> GetAllReportsInstalled();
}

public interface IReportLocationInfo
{
     void SomeMethod();
}

And then implement your concrete factories inside "plug-in" assemblies (program A):

public class MyReportFactory : IReportFactory
{
    // ...
}

And then cast each plugin to a IReportFactory after loading inside program B.

Groo