【问题标题】:Dynamically create a generic type which use the type itself as generic parameter动态创建使用类型本身作为泛型参数的泛型类型
【发布时间】:2017-05-05 11:53:48
【问题描述】:

这里有一个虚拟代码来解释我的问题:

public class A<TX, TA> where TA : A<TX, TA>
{

}

public void Do()
{
   var doy = typeof(A<,>).MakeGenericType(typeof(string), null/*??????*/));
}

如果我无法识别我的类型以将其用作参数,我如何从我的泛型类型中创建一个类型?

感谢您的帮助。

编辑,静态执行的示例:

public abstract class A<TX, TA> where TA : A<TX, TA>
{
    public TA ChainMethod()
    {
        return (TA)this;
    }
}

public class AConcrete : A<string, AConcrete>
{
    public AConcrete OtherMethod()
    {
    return this;
    }
}

public class App
{
    public static void Start()
    {
    new AConcrete().ChainMethod().ChainMethod().OtherMethod();
    }
}

【问题讨论】:

  • 如果这是 CRTP - 它会变得非常难看;你会如何用 C# 来表达它? A&lt;string, A&lt;string, A&lt;string, A&lt;string, ........ ?
  • 你不能。但是添加“动态”是一条红鲱鱼 - 它不像有任何方法可以静态地做到这一点。 A&lt;string, ???&gt; -- 我如何扩展“???”?一定有一个基地在某个地方。该类本身是合法的,但您至少需要一个其他类来引导它。 Eric Lippert's comments 关于这令人困惑并且可能无法实现您想要的东西仍然有效。
  • 你能解释一个更高级的需求吗?
  • 您希望动态执行该代码的哪一部分?动态生成AConcrete?无论如何,您都需要将其作为单独的类型。你不能调用.MakeGenericType 来传递你正在创建的相同类型。您可以生成一个从泛型类型继承的类型,并将其自身作为类型参数,正如 C# 代码所做的那样(使用 ModuleBuilder.DefineType)——但这是在运行时创建类型,而不仅仅是实例化泛型类型。
  • 这是可能的,但在后一种情况下你仍然需要DefineType,这听起来比必要的复杂得多。考虑一些具有非泛型类的泛型方法的解决方案,这些方法往往要简单得多。或者使用DictionaryTypes 的某种方法来映射事物。不要太沉迷于泛型——无论如何,一旦你在运行时做事,类型安全就不是很好了。

标签: c# .net generics


【解决方案1】:

您需要设计类层次结构。似乎还没有完全到位。请查看此示例,希望它能给您一个想法:

abstract class BaseBuilder<TBrick>
{
    public BaseBuilder<TBrick> AddBrick(TBrick brick)
    {
        // ...
        return this;
    }
}

class Builder : BaseBuilder<ConcreteBrick>
{
    public Builder AddRoof()
    {
        // ...
        return this;
    }

    public new Builder AddBrick(ConcreteBrick brick) 
    {
        base.AddBrick(brick);
        return this;
    }
}

它看起来像这样:

new Builder()
    .AddBrick(new ConcreteBrick())
    .AddBrick(new ConcreteBrick())
    .AddRoof();

如果您不按照我的建议使用 new 关键字覆盖方法,我认为您将无法使用继承链接调用。尽管如果您放弃链接调用的想法,您可以轻松实现。

【讨论】:

  • 您的示例中没有继承。
  • 很好地尝试了您的编辑,但由于 AddBrick() 的返回类型是 BaseBuilder,而不是“Builder”,因此无法调用 AddRoof() :)
  • @Manofgoa 请查看更新。我不喜欢 new 那里的关键字,但这是你可以逃脱的方式。
  • 是的,“new”关键字是一种解决方案(例如,WebForms 使用它来公开强类型的 MasterPage)。但我的观点是尽量减少将从我的基类继承的开发人员编写的代码。
  • @Manofgoa 我认为如果不像我建议的那样使用new 覆盖方法,您将无法使用继承链接调用。尽管如果您放弃链接调用的想法,您可以轻松实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多