【问题标题】:How do I apply a "template" or "skeleton" of code in C# here?如何在这里应用 C# 中的代码“模板”或“骨架”?
【发布时间】:2010-02-26 15:04:54
【问题描述】:

在我的业务层,我需要很多很多遵循模式的方法:

public BusinessClass PropertyName
{
    get
    {
        if (this.m_LocallyCachedValue == null)
        {
            if (this.Record == null)
            {
                this.m_LocallyCachedValue = new BusinessClass(
                     this.Database, this.PropertyId);
            }
            else
            {
                this.m_LocallyCachedValue = new BusinessClass(
                     this.Database, this.Record.ForeignKeyName);
            }
        }
        return this.m_LocallyCachedValue;
    }
}

我仍在学习 C#,我正在尝试找出编写此模式的最佳方法,并向每个遵循此模式的业务层类添加方法,并替换正确的类型和变量名。

BusinessClass是必须替换的类型名,PropertyName、PropertyId、ForeignKeyName、m_LocallyCachedValue都是应该替换的变量。

这里可以使用属性吗?我需要反思吗?如何编写我在一个地方提供的骨架,然后只写一两行包含替换参数并让模式自行传播?

编辑:修改了我的误导性标题——我希望找到一个不涉及代码生成或复制/粘贴技术的解决方案,而是能够在某些基类中编写一次代码的骨架形式并将其“实例化”为许多子类作为各种属性的访问器。

编辑:这是我的解决方案,如建议的那样,但所选回答者未实施。

// I'll write many of these...
public BusinessClass PropertyName
{
    get
    {
        return GetSingleRelation(ref this.m_LocallyCachedValue, 
            this.PropertyId, "ForeignKeyName");
    }
}

// That all call this.
public TBusinessClass GetSingleRelation<TBusinessClass>(
    ref TBusinessClass cachedField, int fieldId, string contextFieldName)
{
    if (cachedField == null)
    {
        if (this.Record == null)
        {
            ConstructorInfo ci = typeof(TBusinessClass).GetConstructor(
                new Type[] { this.Database.GetType(), typeof(int) });
            cachedField = (TBusinessClass)ci.Invoke(
                new object[] { this.Database, fieldId });
        }
        else
        {
            var obj = this.Record.GetType().GetProperty(objName).GetValue(
                this.Record, null);
            ConstructorInfo ci = typeof(TBusinessClass).GetConstructor(
                new Type[] { this.Database.GetType(), obj.GetType()});
            cachedField = (TBusinessClass)ci.Invoke(
                new object[] { this.Database, obj });
        }
    }

    return cachedField;
}

【问题讨论】:

    标签: c# reflection templates attributes


    【解决方案1】:

    查看CodeSmith。他们有免费试用版,如果你想购买它也不会太贵。我已经使用过它,它非常适合基于数据库生成代码(我猜你正在这样做)。设置好模板后,您可以随时重新生成代码。您可以让它直接从数据库模式中读取属性名称,也可以输入要使用的值。如果你想一次生成一整批类,我相信你甚至可以让它从文件中读取值。

    【讨论】:

    • 我还没有看过那个包,但我希望有一个非代码生成的解决方案。我目前正在使用 Microsoft SQLMETAL,这一层是建立在它之上的(无论好坏)。
    • 这也是一个很好的功能,但我希望避免任何复制/粘贴类型的解决方案,以便我可以根据需要对模板进行更改。
    【解决方案2】:

    您可以使用 T4 模板签出。我不太确定哪个是 T4 的“资源”,但我在 VisualStudioMagazine 中找到了一个很好的 article

    它是免费的,具有易于使用的语法,并且实际上被许多项目(例如 Subsonic)用于代码生成,因此您应该能够找到一些真实世界的场景。

    【讨论】:

      【解决方案3】:

      您可以使用 CodeSmith 或 MyGeneration 等进行代码生成。您可能会在某处存储类和属性的列表,然后将该数据传递给代码生成器。您可能希望在编译解决方案之前使用预构建事件重新生成这些类。

      或者,您可以将此功能烘焙到基类或辅助方法中。

      public BusinessClass MyProperty
      {
          get { return GetCached("MyProperty", "PropertyId", "FKName", "LocalValue"); }
      }
      

      GetCached() 的正文由您决定,但它与您发布的内容基本相同,将变量作为参数传入。

      如果一个类中的所有属性的这些值中的任何一个都相同,那么您当然可以从实例变量中提取它们,并且只将那些因每个属性而异的东西传递给 GetCached()。

      底线:如果有办法将您正在做的事情的逻辑抽象为基本方法,以便使用该逻辑成为单线,那么这可能是最好的方法,因为当你有特殊情况时更容易覆盖。如果你不能这样做,代码生成可以为你完成繁重的工作,但你需要解决诸如我什么时候重新生成我如何重新生成等

      【讨论】:

      • 对,我同意一代是为了鸟类。我试图编写一个方法来完成它,但我必须传入this.Record.ForeignKeyName,但我不能这样做,因为 this.Record 可能为 NULL ...您是否建议我传入字符串“this.Record” .ForeignKeyName”并使用反射?
      • @Scott: 与其将值传递给方法,为什么方法不直接访问属性?例如,如果您在同一个基类中同时声明 GetCached()Record,则 GetCached() 可以进行自己的空值检查。您只希望方法参数是在每个调用站点发生变化的东西。这是有道理的,还是我误解了什么?
      • 谢谢。请参阅 GetCached 正文的(已编辑)问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-08
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      相关资源
      最近更新 更多