不使用“Internal”的 C# 类设计或“静态”?

发布于 2024-08-04 20:17:19 字数 2722 浏览 11 评论 0原文

我想在类中实例化一堆数据,并且对于每个变量,我想确保还定义了一组特定的方法。 IE:

[TypeA] VarA
[TypeB] VarB
[TypeC] VarC

FA1() which is a function of VarA and VarB
FA2() which is a function of VarA and VarC

FB1() which is a function of VarB and VarA
FB2() which is a function of VarB and VarC
...

由于会有大量变量(因此会有更多函数),我想将源代码分成可管理的块。因此,我正在寻找一种自动方法来确保每个变量的所有函数都被实例化。

我想出了 3 种可能的方法来组织我的代码,但我对每种方法都不太满意,我正在寻找或建议哪种方法更好(或者即使我错过了完全不同的实现方法):

<强>1。部分类

partial class Base
{
}

partial class Base 
{
  [TypeA] VarA;

  FA1 { .. };  // function of VarA and VarB
  FA2 { .. };  // function of VarA and VarC
}


partial class Base 
{
  [TypeB] VarB;

  FB1 { .. };  // function of VarB and VarA
  FB2 { .. };  // function of VarB and VarC
}

优点:

  1. 简单
  2. 变量只能从基类内部访问。
  3. 如果有两个相同类型的变量,那么每个变量的函数可以不同地实现自己的函数。

缺点:

  1. 无法自动确保为每个变量创建所有函数,
  2. 需要手动确保每个函数名称之间不存在名称冲突。

请注意,缺点可以通过某种代码生成器来解决(也许是时候学习 T4??)


2。内部类

class Base 
{
  internal [ClassA] ObjA = new [ClassA]();
  internal [ClassB] ObjB = new [ClassB]();
}

class [BaseClassA]
{
  public [TypeA] VarA;

  public virtual F1 { .. };
  public virtual F2 { .. };
}

class [ClassA] : [BassClassA]
{
  public override F1 { .. };  // function of VarA and ObjB.VarB
  public override F2 { .. };  // function of VarA and ObjC.VarC
}
...

优点:

  1. 类层次结构强制创建所有函数并访问变量。
  2. 通过使用虚拟函数可以创建函数的实例特定实现。

缺点:

  1. 使用内部意味着数据在程序集中任何地方都可见。

3.静态数据

abstract class Data
{
   static [TypeA] VarA;
   static [TypeB] VarB;
   ...
}

abstract class [BaseClassA] : Data
{
  public virtual F1 { .. };
  public virtual F2 { .. };
}

class [ClassA] : [BassClassA]
{
  public override F1 { .. };  // function of VarA and VarB
  public override F2 { .. };  // function of VarA and VarC
}

class Base 
{
 [ClassA] ObjA = new [ClassA]();
 [ClassB] ObjB = new [ClassB]();
}

优点:

  1. 系统确保所有例程都被实例化
  2. 数据不会在程序集周围爆炸
  3. 在每个函数中,您可以按照“部分类”解决方案直接引用其他变量

缺点:

  1. 使用静态 闻起来就像我刚刚重新发明了全球数据。

我想要的是以某种方式挑选每个方法的最佳点:

  1. 访问“部分类”和“静态”方法的变量的直接方式
  2. “部分类”方法的本地数据
  3. 自动执行该方法的函数实现“内部”和“静态”方法。

我想避免:

  1. “部分类”中缺乏强制函数生成
  2. “内部”方法中数据的全局访问
  3. “静态”方法中全局数据的重新发明

如果我要让我的德鲁瑟斯我想说,我想要的是以某种方式将接口应用于变量的实例 - 例如:

[TypeA] VarA : IFunctions;
[TypeB] VarB : IFunctions;

并以某种方式让编译器从接口名称和可用名称自动生成最终函数名称。

因此,人们可以建议他们更愿意实施这 3 种方法中的哪一种,或者建议任何其他可能适合的方法。

I have a bunch of data I want to instantiate in a class, and for each variable I want to ensure a specific set of methods are also defined. IE:

[TypeA] VarA
[TypeB] VarB
[TypeC] VarC

FA1() which is a function of VarA and VarB
FA2() which is a function of VarA and VarC

FB1() which is a function of VarB and VarA
FB2() which is a function of VarB and VarC
...

As there will be a large number of variables (and hence even more functions) I want to split my source code up into manageable chunks. So I am looking for an automatic way of ensuring that all of the functions for each variable are instantiated.

I have come up with 3 possible methods to organize my code and I am not too happy with each of them and I am looking or advice as to which method is the better (or even if I have missed a completely different implementation method):

1. Partial Class

partial class Base
{
}

partial class Base 
{
  [TypeA] VarA;

  FA1 { .. };  // function of VarA and VarB
  FA2 { .. };  // function of VarA and VarC
}


partial class Base 
{
  [TypeB] VarB;

  FB1 { .. };  // function of VarB and VarA
  FB2 { .. };  // function of VarB and VarC
}

Pros:

  1. Simple
  2. Variables can only be accessed from within class Base.
  3. If there are two variables of the same type then the functions for each variable can implement its own function differently.

Cons:

  1. Cannot automatically ensure that all functions are created for each variable
  2. Need to manually ensure that there are no name collisions between each function name.

Note that the Cons may be solved by a code generator of some sort (maybe time to learn T4??)


2. Internal class

class Base 
{
  internal [ClassA] ObjA = new [ClassA]();
  internal [ClassB] ObjB = new [ClassB]();
}

class [BaseClassA]
{
  public [TypeA] VarA;

  public virtual F1 { .. };
  public virtual F2 { .. };
}

class [ClassA] : [BassClassA]
{
  public override F1 { .. };  // function of VarA and ObjB.VarB
  public override F2 { .. };  // function of VarA and ObjC.VarC
}
...

Pros:

  1. Class hierarchy enforces that all functions are created and that variables are there to be accessed.
  2. Through use of virtual functions can create instance specific implementations of functions

Cons:

  1. Use of Internal means that data is visible everywhere in the assembly.

3. Static data

abstract class Data
{
   static [TypeA] VarA;
   static [TypeB] VarB;
   ...
}

abstract class [BaseClassA] : Data
{
  public virtual F1 { .. };
  public virtual F2 { .. };
}

class [ClassA] : [BassClassA]
{
  public override F1 { .. };  // function of VarA and VarB
  public override F2 { .. };  // function of VarA and VarC
}

class Base 
{
 [ClassA] ObjA = new [ClassA]();
 [ClassB] ObjB = new [ClassB]();
}

Pros:

  1. System ensures that all routines are instantiated
  2. Data is not blasted all around the assembly
  3. Within each function you can directly reference the other variables as per the 'partial class' solution

Cons:

  1. The use of static smells like I have just re-invented global data.

What I want is to somehow cherry pick the best points of each method:

  1. The direct manner of accessing variables of the "Partial class" and "Static" methods
  2. The local data of the "Partial class" method
  3. The automatic enforcing of function implementation of the "Internal" and "Static" methods.

And I want to avoid:

  1. The lack of enforcing function generation in the "Partial class"
  2. The global access of data in the "Internal" method
  3. The re-invention of global data in the "Static" method

If I was going to have my druthers I'd say that what I want is to somehow apply an interface to an instance of a variable - like:

[TypeA] VarA : IFunctions;
[TypeB] VarB : IFunctions;

And somehow have the compiler auto-generate the final function names from the interface names and the vaiable name.

So can people suggest which of the 3 methods they would prefer to implement, or suggest any other methods that may suit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

佞臣 2024-08-11 20:17:19

您提供了四个代码示例,“简单”版本以便您可以解释问题,然后提供 3 个“更好”的解决方案来解决问题。唯一不言自明的版本是简单版本。所以,我想到了明年必须维护的可怜的开发人员(可能是忘记自己做了什么的你)。

那么,您是否可以考虑一种完全不同的机制来“确保每个变量的所有函数都被实例化”。您提到愿意在编译时使用 T4 自动生成存根。使用 Microsoft FxCop< /a> 捕获任何您忘记添加内容的实例。

如果您不熟悉它,Microsoft FxCop(也嵌入在某些版本的 Visual Studio 中)扫描已编译的程序集,并针对您的代码评估数百条框架规则,从变量的正确拼写和大小写到未使用的局部变量。

虽然我个人同意 Microsoft 捆绑到 FxCop 中的大部分规则,但我认为它的真正美妙之处在于能够创建自己的规则。我创建了添加到 FxCop 中的规则,以强制执行 CRUD 原则,例如,如果您有一个 CreateXxx 方法,则必须有一个DeleteXxx 方法等。因此,如果您确定一个与您想要的模式匹配的类,您可以获得所有变量 {A, B, C} 的列表,然后保证 FuncAB(A, B) 存在并且 FuncAC(A, C) 存在等。

然后,即使是当初级开发人员下次实现 IBiVariableFunction 并忘记对上的函数时,他会被 FxCop 抓住。

干杯,阿德里安

You present four code samples, the 'simple' version so that you can explain the problem and then 3 'better' solutions to fix the problem. The only version that was self-explanatory was the simple version. So, I'm thinking of the poor developer that has to come in a maintain this next year (which might be you after forgetting what you did).

So, could you consider a different mechanism altogether for "ensuring that all of the functions for each variable are instantiated". You mentioned a willingness to use T4 to auto-generate stubs for you during compile time. What about using Microsoft FxCop to catch any instances where you forgot to add something.

If you're not familiar with it, Microsoft FxCop (also embedded in some flavors of Visual Studio) scans the compiled assemblies and evaluates hundreds of framework rules against your code, from proper spelling and casing of variables to unused locals.

While I personally agree with most of the rules that Microsoft has bundled into FxCop, I think the real beauty of it is the ability to create your own rules. I have created rules that I add to FxCop that enforces CRUD principles, such as if you have a CreateXxx method, you must have a DeleteXxx method etc. So, if you identify a class that matches the pattern you desire, you can get a list of all variables {A, B, C} and then guarantee that FuncAB(A, B) exists and that FuncAC(A, C) exists etc.

Then, even a junior developer would be caught out by FxCop the next time he implements IBiVariableFunction and forgets a function on a pair.

Cheers, Adrian

屌丝范 2024-08-11 20:17:19

你的问题基本上没有任何实际背景,很难理解。您提供了三个“答案”,但没有明确的问题(imo)。

坦率地说,如果您想确保您所说的每个“变量”都有关联的方法,您应该考虑使用接口,并使用属性代替字段(因为接口不能指定字段。)

interface IAStuff {
    TypeA AProp { get; }
    void DoSomethingToA();
}

interface IBStuff {
    TypeB BProp { get; }
    void DoSomethingToB();
}

public class Foo : IAStuff, IBStuff {
    TypeA AProp { get; private set; }
    TypeB BProp { get; private set; }

    void DoSomethingToA() { ... }
    void DoSomethingToB() { ... }
}

如果类声明它实现了接口,则它别无选择,只能提供指定的成员,否则将无法编译。

希望这有帮助,

-Oisin

Your question is largely without any real context and is difficult to understand. You have provided three "answers" without a clear question (imo.)

Frankly, if you want to ensure that each "variable" as you call it has associated methods, you should consider using interfaces, and use properties in the place of fields (since interfaces cannot specify fields.)

interface IAStuff {
    TypeA AProp { get; }
    void DoSomethingToA();
}

interface IBStuff {
    TypeB BProp { get; }
    void DoSomethingToB();
}

public class Foo : IAStuff, IBStuff {
    TypeA AProp { get; private set; }
    TypeB BProp { get; private set; }

    void DoSomethingToA() { ... }
    void DoSomethingToB() { ... }
}

If the class declares that it implements an interface, it has no choice but to provide the specified members or it will not compile.

Hope this helps,

-Oisin

少女净妖师 2024-08-11 20:17:19

你能不能不使用建议2,而是使用protected 而不是internal?

Could you not use suggestion 2 but with protected instead of internal?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文