c# 生成c#代码_C#内部关键字是否有代码味道?

c# 生成c#代码

In this post, I am going to show why I think the internal keyword, when put on class members, is a code smell and suggest better alternatives.

在本文中,我将展示为什么我认为将内部关键字放在类成员上时会产生代码味道,并提出更好的替代方法。

内部关键字是什么? (What is the internal keyword?)

In C# the internal keyword can be used on a class or its members. It is one of the C# access modifiers. Internal types or members are accessible only within files in the same assembly. (C# internal keyword documentation).

在C#中,内部关键字可用于类或其成员。 它是C# 访问修饰符之一 。 内部类型或成员只能在 同一程序集中的文件中访问。 ( C#内部关键字文档 )。

为什么我们需要内部关键字? (Why we need the internal keyword?)

“A common use of internal access is in component-based development because it enables a group of components to cooperate in a private manner without being exposed to the rest of the application code. For example, a framework for building graphical user interfaces could provide Control and Form classes that cooperate by using members with internal access. Since these members are internal, they are not exposed to code that is using the framework.” (C# internal keyword documentation)

内部访问的常见用法是基于组件的开发,因为它使一组组件能够以私有方式进行协作,而不会暴露给其余的应用程序代码 。 例如,用于构建图形用户界面的框架可以提供Control和Form类,这些类通过使用具有内部访问权限的成员进行协作。 由于这些成员是内部成员,因此它们不会接触使用该框架的代码。” ( C#内部关键字文档 )

These are the use cases I saw for using the internal keyword on a class member:

这些是在类成员上使用internal关键字的用例:

  • Call a class’s private function within the same assembly.

    在同一程序集中调用类的私有函数。
  • In order to test a private function, you can mark it as internal and exposed the dll to the test DLL via InternalsVisibleTo.

    为了测试私有函数,您可以将其标记为内部函数,并通过InternalsVisibleTo将dll暴露给测试DLL。

Both cases can be viewed as a code smell, saying that this private function should be public.

两种情况都可以看作是代码的味道,表示此私有功能应该是公共的。

让我们看一些例子 (Let's see some examples)

Here is a simple example. a function in one class wants to access a private function of another class.

这是一个简单的例子。 一个类中的函数想要访问另一类的私有函数。

class A{
	public void func1(){
		func2();
	}
	private void func2(){}
}

class B{
	public void func(A a){
		a.func2(); //Compilation error 'A.func2()' is inaccessible due to its protection level
	}
}

The solution is simple — just mark A::func2 as public.

解决方案很简单-只需将A :: func2标记为public。

Let's look at a bit more complex example:

让我们来看一个更复杂的示例:

public class A{
	public void func1(){}
	private void func2(B b){}
}

internal class B{
	public void func3(A a){		
		a.func2(this); //Compilation error 'A.func2(B)' is inaccessible due to its protection level
	}
}

What’s the problem? just mark func2 as public as we did before.

有什么问题? 就像我们以前一样将func2标记为公共。

public class A{
	public void func1(){ ... }
	public void func2(B b){ ...} // Compilation error: Inconsistent accessibility: parameter type 'B' is less accessible than method 'A.func2(B)' 
}

internal class B{
	public void func3(A a){		
		a.func2(this); 
	}
}

But we can’t ?. B is an internal class so it cannot be part of the signature of a public function of a public class.

但是我们不能? B是内部类,因此它不能成为公共类的公共功能的签名的一部分。

Those are the solutions I found, ordered by easiness:

这些是我发现的解决方案,按轻松程度排序:

  1. Mark the function with the internal keyword

    用内部关键字标记功能
public class A{
	public void func1(){ }
	internal void func2(B b){}
}

internal class B{
	public void func3(A a){		
		a.func2(this); 
	}
	
}

2. Create an internal interface

2.创建一个内部接口

internal interface IA2{
	void func2(B b);
}

public class A:IA2{
	public void func1(){
		var b = new B();
		b.func3(this);
	}
	void IA2.func2(B b){} //implement IA2 explicitly because func2 can't be public
}

internal class B{
	public void func3(A a){ 
		((IA2)a).func2(this); //use interface instead of class to access func2	
	}
	
}

3. Extract A.func2 to another internal class and use it instead of A.func2.

3.将A.func2提取到另一个内部类,并使用它代替A.func2。

internal class C{
	public void func2(B b){
	 //extract A:func2 to here
	}
}

public class A{
	public void func1(){}
	private void func2(B b){
		new C().func2(b); 
	}
}

internal class B{
	public void func3(){	//a is no longer needed	
		new C().func2(this); //use internal class instead of private function
	}
	
}

4. Decouple the function from internal classes and make it public. This is much dependant on what the function is doing with its inputs. decouple the internal classes can be very easy, very hard and even impossible (without ruing the design).

4.将函数与内部类分离,并将其公开。 这在很大程度上取决于函数对其输入的作用。 内部类的解耦可能非常容易,非常困难,甚至是不可能的(不破坏设计)。

但是我们没有使用接口的公共类…… (But we don’t have public classes we use interfaces…)

Let's look at some more real-world example:

让我们看一些更真实的例子:

public interface IA{
	void func1();
}

internal class A : IA {
	public void func1(){}
	private void func2(B b){}
}

internal class B{
	public void func3(IA a){		
		a.func2(this);  //Compilation error IA' does not contain a definition for 'func2' and no extension method 'func2' accepting a first argument of type 'IA' could be found

	}	
}

Let's see how the previous solutions are adapted to this example:

让我们看看以前的解决方案如何适应此示例:

  1. Mark function with Internal. this means you will need to cast to class in order to call the function so This will work only if class A is the only one that implements the interface, meaning IA is not mocked in tests and there isn’t another production class that implements IA.

    用内部标记功能。 这意味着您将需要强制转换为类才能调用该函数,因此仅当类A是唯一实现该接口的类时才有效 ,这意味着IA在测试中没有被模拟,并且没有另一个实现IA的生产类。

public interface IA{
	void func1();
}

internal class A : IA {
	public void func1(){}
	internal void func2(B b){}
}

internal class B{
	public void func3(IA a){		
		((A)a).func2(this); //cast to A in order to accses func2

	}	
}

2. Create an internal interface that extends the public interface.

2.创建一个扩展公共接口的内部接口。

internal interface IExtendedA : IA{
	void func2(B b);
}

public interface IA{
	void func1();
}

internal class A : IExtendedA {
	public void func1(){}
	public void func2(B b){}
}

internal class B{
	public void func3(IExtendedA a){		
		a.func2(this);

	}	
}

3. Extract A.func2 to another internal class and use it instead of A.func2.

3.将A.func2提取到另一个内部类,并使用它代替A.func2。

4. Decouple the function from internal classes and add it to the public interface.

4.将函数与内部类解耦,并将其添加到公共接口。

We can see that the internal keyword is the easiest solution, but there are other solutions using the traditional building blocks of OOP: classes and interfaces. We can see that the 2nd solution — adding an internal interface is not much harder than marking the function with the internal keyword.

我们可以看到, 内部关键字是最简单的解决方案 ,但是还有其他使用OOP传统构建模块的解决方案:类和接口 。 我们可以看到第二种解决方案-添加内部接口并不比用internal关键字标记功能难得多。

为什么不使用内部关键字? (Why not use the internal keyword?)

As I showed in the previous examples, using the internal keyword is the easiest solution. But you are going to have a hard time in the future if you will need to:

如我在前面的示例中所示,使用internal关键字是最简单的解决方案 。 但是,如果您需要:

  • Move the public class A to another DLL (since the internal keyword will no longer apply to the same dll)

    将公共类A移到另一个DLL(因为内部关键字将不再适用于同一dll)
  • Create another production class that implements IA

    创建另一个实现IA的生产类
  • Mock IA in tests

    在测试中模拟IA

You may think “But this is just one line of code, I or anyone else can change it easily if needed”. Now you have one line of code that looks like that:

您可能会认为“但这只是一行代码,如果需要,我或其他任何人都可以轻松更改它”。 现在,你有一行代码看起来像这样:

((MyClass)a).internalFunction

but if others will need to call this function too this line will be copy-pasted around inside the DLL.

但是如果其他人也需要调用此函数,则此行将被复制粘贴到DLL内部。

我的结论 (My Conclusion)

I think marking a class member with the internal keyword is a code smell. In the examples I showed above it is the easiest solution, BUT can cause problems in the future. Creating an internal interface is almost as easy and more explicit.

我认为用内部关键字标记类成员是一种代码味道 。 在上面显示的示例中,这是最简单的解决方案,但BUT将来可能会引起问题。 创建内部接口几乎一样容易,也更加明确。

与C ++比较 (Compare to C++)

The C++ “friend” keyword is similar to the C# internal keyword. It allows a class or a function to access private members of a class. The difference is it allows access to specific class or function and not all the classes in the same DLL. In my opinion, this is a better solution than the C# internal keyword.

C ++“ friend”关键字类似于C#内部关键字。 它允许类或函数访问类的私有成员。 不同之处在于,它允许访问特定的类或函数,而不是访问同一DLL中的所有类。 我认为,这是比C#内部关键字更好的解决方案。

进一步阅读 (Further Reading)

Practical uses for the "internal" keyword in C#Why does C# not provide the C++ style 'friend' keyword?

C#中“内部”关键字的实际用法 为什么C#不提供C ++样式的“朋友”关键字?

翻译自: https://www.freecodecamp.org/news/is-the-c-internal-keyword-a-code-smell/

c# 生成c#代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值