【问题标题】:Generics in C#, using type of a variable as parameter [duplicate]C#中的泛型,使用变量的类型作为参数[重复]
【发布时间】:2011-01-07 15:33:37
【问题描述】:

我有一个通用方法

bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

我如何通过以下方式使用该方法:

Type t = entity.GetType();
DoesEntityExist<t>(entityGuid, transaction);

我不断收到愚蠢的编译错误:

类型或命名空间名称“t”可以 找不到(您是否缺少使用 指令还是程序集引用?)

DoesEntityExist<MyType>(entityGuid, transaction);

完美运行,但我不想每次都使用 if 指令来调用具有单独类型名称的方法。

【问题讨论】:

标签: c# .net generics types


【解决方案1】:

关于泛型的重点是为编译时类型提供安全性——这意味着需要在编译时知道类型。

可以调用只有在执行时才知道类型的泛型方法,但你必须使用反射:

// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
                             .MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });

伊克。

您能否将您的 调用 方法改为泛型,并将您的类型参数作为类型参数传递,从而将决策推到更高的堆栈级别?

如果您能向我们提供有关您正在做的事情的更多信息,那将会有所帮助。有时你可能需要像上面那样使用反射,但是如果你选择了正确的点来做,你可以确保你只需要做一次,并且让低于该点的所有东西都以正常的方式使用类型参数。

【讨论】:

  • 我认为这个答案中最重要的是ick。那和编译时类型安全.
  • @Mitch:问题在于有时这是必要的。它很丑陋,应该尽可能避免......但偶尔你需要它。
  • @JonSkeet: 有没有办法使用dynamic 关键字来适应这种情况?
  • @MoslemBenDhaou:不,因为这里没有用于类型推断的实例。
  • @MoslemBenDhaou:你可以通过一个中间泛型方法使用dynamic 来推断类型。如果这还不够信息,请提出一个新问题 - 它与这个问题有很大不同,因此在 cmets 中追求它并不理想。
【解决方案2】:

解决这个问题的一种方法是使用隐式转换:

bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

这样称呼它:

DoesEntityExist(entity, entityGuid, transaction);

更进一步,你可以把它变成一个扩展方法(它需要在一个静态类中声明):

static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

这样称呼:

entity.DoesEntityExist(entityGuid, transaction);

【讨论】:

  • 这太棒了!有什么缺点吗?似乎比使用反射更优雅地解决原始问题??
  • 只有在声明类型足够的情况下才有效。如果实体被声明为对象怎么办? JonSkeet 的解决方案创建了泛型版本,其中 T 是真实类型,而不是声明的类型。
  • 我不知道使用T约束可以让你在调用方法时绕过类型参数。当我可以做Sort(input)时,我试图找出类似Sort&lt;typeof(input)&gt;(input)的东西!
【解决方案3】:

我不确定我是否正确理解了您的问题,但您可以这样编写代码:

bool DoesEntityExist<T>(T instance, ....)

您可以通过以下方式调用该方法:

DoesEntityExist(myTypeInstance, ...)

这样你就不需要显式编写类型,框架会自动从实例中获取类型。

【讨论】:

    【解决方案4】:

    你不能按照你描述的方式使用它。关于泛型类型的要点是,尽管您可能在“编码时”不知道它们,但编译器需要能够在编译时解析它们。为什么?因为在底层,编译器会离开并为“开放”泛型类型的每种不同用法创建一个新类型(有时称为封闭泛型类型)。

    也就是说,编译后,

    DoesEntityExist<int>
    

    是不同的类型
    DoesEntityExist<string>
    

    这就是编译器能够确保编译时类型安全的方式。

    对于您描述的场景,您应该将类​​型作为可在运行时检查的参数传递。

    正如其他答案中提到的那样,另一个选项是使用反射从开放类型创建封闭类型,尽管这可能在我所说的极端利基场景之外的任何情况下被推荐。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-04
      • 1970-01-01
      • 1970-01-01
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多