【问题标题】:C# generics wrapper generatorC# 泛型包装器生成器
【发布时间】:2013-04-09 20:08:19
【问题描述】:

我正在寻找一个代码生成器(最好有源代码),它允许我为我的代码中的泛型类生成包装类(使用反射)。

我已经进行了一些搜索,但似乎找不到任何可以在这里满足我需要的东西,所以我想在开始编写自己的内容之前先在这里问一下。最终,我可能不得不自己写,但如果有人已经写过这样的东西,我至少想抢先一步。

解释我想要它做什么有点困难,但是生成器应该允许我指定我希望它为哪些泛型类生成包装器。它应该检查我指定的 DLL 中的类型,以确定哪些类型适合基于泛型类中的 where 约束。我在 linqpad 中编写了一些示例代码,并在“生成的代码”部分提供了示例输出。如您所见,它会根据泛型类中指定的约束生成所有类的组合。

我为什么要这样做?我有很多通用类,每个类都有许多类型参数(其中许多类型参数超过 10 个),我希望简化客户端代码(这还需要一些自定义工作以及一个代码生成器,该代码生成器会生成每个组合可能,但我可以处理)。完成之后,我可以将底层泛型类重构为更简单(不影响客户端代码),并且不需要像目前那样多的类型参数,这在现阶段并不完全可能。

void Main()
{
    var x = new GenBothFooAgainBarAgain();
    var y = new GenFFoo();
    var z = new GenFFooAgain();
    var a = new GenBothWithChildFooBarFooChild();
    var b = new GenBothWithChildFooBarAgainFooChild();
}

//////////////////////////////////Generated code ////////////////////////////////////
public class GenBothFooBar : GenBoth<Foo, Bar> {}
public class GenBothFooAgainBar : GenBoth<FooAgain, Bar> {}
public class GenBothFooBarAgain : GenBoth<Foo, BarAgain> {}
public class GenBothFooAgainBarAgain : GenBoth<FooAgain, BarAgain>{}
public class GenFFoo : GenF<Foo>{}
public class GenFFooAgain : GenF<FooAgain>{}

public class GenBothWithChildFooBarFooChild : GenBothWithChild<Foo, Bar, FooChild> {}
//public class GenBothWithChildFooAgainBarFooChild : GenBothWithChild<FooAgain, Bar, FooChild> {} - illegal - Don't generate this as FooChild doesn't inherit from FooAgain
public class GenBothWithChildFooBarAgainFooChild : GenBothWithChild<Foo, BarAgain, FooChild> {}
//public class GenBothWithChildFooAgainBarAgainFooChild : GenBothWithChild<FooAgain, BarAgain, FooChild>{} - illegal - Don't generate this as FooChild doesn't inherit from FooAgain


//////////////////////////////////Generated code ////////////////////////////////////

public class Foo : IFoo
{
    public string foo {get; set;}
}

public class FooChild : Foo, IFooChild
{
    public string fooChild {get; set;}
}

public class Bar : IBar
{
    public string bar {get; set;}
}

public class FooAgain : IFoo
{
    public string foo {get; set;}
}

public class BarAgain : IBar
{
    public string bar {get; set;}
}

public class GenF<F>
where F: class, IFoo, new()
{

}

public class GenBoth<F, B>
where F: class, IFoo, new()
where B: class, IBar, new()
{

}

public class GenBothWithChild<F, B, FChild>
where F: class, IFoo, new()
where B: class, IBar, new()
where FChild: class, F, IFooChild, new()
{

}

public interface IFooChild
{
    string fooChild {get; set;}
}

public interface IFoo
{
    string foo {get; set;}
}

public interface IBar
{
    string bar {get; set;}
}

【问题讨论】:

  • 如果我自己写的话,这看起来是一个好的开始 - stackoverflow.com/questions/8219725/…
  • 有趣的问题,但是这可能是很多的类型。假设有 10 个泛型类型参数(尽管您提到超过 10 个)和 3 个在编译时已知的可以满足每个泛型类型约束的类型,那么这就是为一个创建的 3^10 个类型(~60K 类型)泛型类型定义。不过,好问题,+1
  • 是的,这就是为什么我可能需要编写一些自定义逻辑来防止这么多组合:) 虽然它可能不是那么糟糕,因为我的类型中的约束非常严格,以便使如果您混合和匹配不在一起的类型,编译器会抱怨。我想我会看看情况如何。看起来我要在这个阶段编写自己的代码,我会在完成后发布代码(可能需要一段时间才能开始使用它:)

标签: c# .net generics reflection code-generation


【解决方案1】:

对于使用 c#/.net 知识生成代码,我建议您使用 T4 - Visual Studio 免费提供的 Microsoft 文本模板引擎。感觉就像是 C# 和 ASP.NET 的混合体,所以你应该能够快速投入。

使用设计时模板,您可以指定现有的程序集并像往常一样反映它们,甚至可以使用Visual Studio Automation CodeModel 来获取有关当前解决方案中的类的信息并从中生成代码它。在您构建项目之前,此代码将在 Visual Studio 中生成。

使用运行时模板,您将“准备”如何在设计时生成代码的逻辑,为其提供程序集列表以在运行时处理和生成代码。 p>

不幸的是,Visual Studio 缺少 T4 模板的编辑功能,但有免费工具可用,例如 tangible's T4 Editor

这段代码sn-p可以在T4模板中使用,在mscorlib.dll中查找所有泛型类,并写入输出文件:

<#
    foreach(System.Reflection.TypeInfo type in typeof(string).Assembly
                                                             .DefinedTypes
                                                             .Where(t => t.ContainsGenericParameters))
    {
#><#= type.Name #><<#= string.Join(", ", type.GenericTypeParameters.Select(tp => tp.Name)) #>>
<#  }
#>

希望对你有帮助

【讨论】:

  • 感谢您的提示,我非常了解 t4 模板并自己使用它们。但是,我正在寻找更符合我的要求的东西,我想我希望那里有任何解决方案,如果存在的话,可能会写成使用 t4。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
相关资源
最近更新 更多