简体   繁体   English

C#通用T类TypeOf,这可能吗?

[英]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> Class<T>并且取决于调用代码中的switch语句,它可以是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... 如果为int Class<int> ,等等。

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 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. 如果您要在解决实例“ x”之后对实例x调用相同的操作,则可以考虑使用接口,这将允许您定义对象执行的方法(和属性)而无需定义其类型。

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? 您以后想对x做什么? 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. 另外,如果可以构造它,使x始终是某个基类的实例,则可以将其强制转换为基类。

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. stringintdecimalobject以外没有其他公共基类型,但是它们确实共享一些接口,因此如果以后要对其进行排序,则可以选择Class<IComparable>东西。 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. 我认为进行此切换的最佳方法是为您的不同类型实际实现单独的方法,然后在UI层进行切换。

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). “列表”是真正让我失望的一个,因为它返回null,否则我会说要做一些类似public ReportResult<T> GetReportData<T>(ReportProcedureNameEventArg procedureNameEventArg) where T:struct (然后强制执行类型)编程)。

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. 如果您想通过动力学来尝试它,我想您可以通过使用ReportResult进行鸭子输入来使它基本上那样工作,但是在混合使用List模式时,它也可能会变得混乱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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