Sarit
Sarit

Reputation: 927

Casting an object I receive through reflection

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?

Upvotes: 1

Views: 1369

Answers (5)

vgru
vgru

Reputation: 51224

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.

Upvotes: 0

ybo
ybo

Reputation: 17152

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>
}

Upvotes: 3

jeroenh
jeroenh

Reputation: 26782

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>

Upvotes: 0

leppie
leppie

Reputation: 117240

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?

Upvotes: 0

Graviton
Graviton

Reputation: 83254

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.

Upvotes: 0

Related Questions