简体   繁体   中英

C# Generic T Class TypeOf, is this possible?

I have a class that is generic. Class<T> and depending in the switch statement in the calling code it can be class<int> class<string> class<decimal>

The the method that returns this returns it as an object because the calling code has no idea what it is until after it is set.

Is there a way to do this once I get the object back from the function?

load(object result)
{
    Type t = result.GetType().GetGenericArguments()[0];

    Class<t> x = (Class<t>) result;
}

Or do I have to set up an a check to check for each type it can be. If int then Class<int> , etc...

EDIT:

Here is what I am trying to do, actual code:

public class ReportResult<TP>
{
    public ReportResult()
    {
        ReportHeaders = new List<ReportHeader>();
        ReportViews = new List<IDataAttributeChild<TP>>();
    }

    public List<ReportHeader> ReportHeaders {get;set;}
    public List<IDataAttributeChild<TP>> ReportViews {get;set;}         
}

BAL

    public object GetReportData(ReportProcedureNameEventArg procedureNameEventArg)
    {
        object result = null;

        switch (procedureNameEventArg.SelectedNode.Class)
        {
            case ReportClass.Count:
                var r = new ReportResult<int>
                            {
                                ReportViews = GetCountByReport(procedureNameEventArg),
                                ReportHeaders = GetReportHeaders(procedureNameEventArg.SelectedNode.ReportViewId)
                            };

                result = r;
                break;
            case ReportClass.List:
                break;
            case ReportClass.Date:
                 var r = new ReportResult<datetime>
                            {
                                ReportViews = GetDateSummaryReport(procedureNameEventArg),
                                ReportHeaders = GetReportHeaders(procedureNameEventArg.SelectedNode.ReportViewId)
                            };

                result = r;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
        return result;
    }

The GUI

    public void LoadTreeResult(object result)
    {
        Type t = result.GetType().GetGenericArguments()[0];

        ReportResult<?> fff = (ReportResult<?>)result;


        dgResult.Columns.Clear();

        foreach (var header in result.ReportHeaders)
        {
            dgResult.Columns.Add(
                    new DataGridTextColumn
                    {
                        Header = header.Header,
                        Binding = new Binding(header.Binding)
                    });
        }

        // This would also be a switch depending on a property coming 
        // back to now what class to cast to in order to populate the grid.
        List<ReportCountByView> d = new List<ReportCountByView>();

        foreach (var reportCountByView in result.ReportViews)
        {
            d.Add((ReportCountByView)reportCountByView);
        } 

        dgResult.ItemsSource = d;
    }

This is a layout of the class model in case it might help.

在此处输入图片说明

image of layout

Thanks.

if you are going to call the same operation on the instance 'x' after you resolve it you may think about using an interface, this will allow you to define the methods the object performs (and properties) without defining it's type.

your code may then end up looking something like this

public interface IMyInterface
{
  void PerformOperation();
}

public class MyGeneric<T> : IMyInterface
{
  T Value {get;set;}
  MyGeneric(T val) 
  {
    Value = val;
  }

  void PerformOperation 
  { 
     Console.WriteLine("T is {0}", typeof(T));
     Console.WriteLine("Value is {0}", Value);
  }
}

public void main(string[] args)
{
   IMyInterface inst = null;
   switch (args[0])
   {
    case "string":
       inst = new MyGeneric("hello");
       break;
    case "int":
        inst = new MyGeneric(7);
        break;
    case "decimal"
        inst = new MyGeneric(18.9M);
        break;
    }

   inst.PerformOperation();
}

What do you want to do with x later? Also, if you can architect it such that x will always be an instance of some baseclass, you could just cast it to the base class.

It depends on how you intend to use the generic types later on. string , int and decimal have no common base type other than object , but they do share some interfaces, so you could possibly choose something like Class<IComparable> if you want to sort them later on. Or you could declare generic constraints if you want to use multiple interfaces:

Class<T> where T : IEquatable<T>, IComparable<T>, IFormattable // and so on...

But what it seems like you're asking for doesn't seem possible. The entire premise of generics is to set the type at design time.

My Opinion

If the result is always being used to invoke same members of the class(es), then can make an interface and implement it to the different classes and get the result as the interface. This way you will be able to used different classes yet some same members of the interface that are implemented in those classes

I think the best way to do this switch would be to actually implement seperate methods for your different types, and switch at the UI layer.

For example

public ReportResult<int> GetReportDataCount(ReportProcedureNameEventArg procedureNameEventArg)

public ReportResult<DateTime> GetReportDataDate(ReportProcedureNameEventArg procedureNameEventArg)

public void GetReportDataList(ReportProcedureNameEventArg procedureNameEventArg)

The "List" one is the one that really throws me off, because it returns null, otherwise I'd say do something like public ReportResult<T> GetReportData<T>(ReportProcedureNameEventArg procedureNameEventArg) where T:struct (and then enforce the types programatically).

If you want to try it with dynamics, I think you could make it work that way basically by doing duck typing with the ReportResult, but It might get messy with your List mode in the mix too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM