我正在使用C#4.0编写一个DLL,它将被几个基于C#.NET的桌面应用程序使用(让他们称之为AppA和AppB)。要求AppA能够使用某些课程。选定的字段/属性/功能甚至不可用于AppB。我的方法是对这些属性使用internal
修饰符,并通过在DLL的InternalsVisibleTo
属性中指定AppA的程序集名称来授予对AppA的访问权限。但是在某些属性中也需要internal
修饰符,这些属性将在DLL的其他部分中访问但不能被AppA访问。现在似乎有太多internal
暴露给AppA,而AppA无法访问它。
换句话说,请考虑以下属性:
class A
{
internal int ReallyInternal {get; set;}
internal int AppAInternal {get; set;}
}
如果我对AppA使用InternalsVisibleTo
属性,那么ReallyInternal
和AppAInternal
属性都会向AppA公开 - 其中ReallyInternal
不应该公开APPA。
如何解决这个问题?有没有其他方法可以实现这种情况?
背景
在进入InternalsVisibleTo
方法之前,我们想到了其他方法,比如拥有不同的界面等。我写的类库将由多个应用程序使用。我希望各种应用程序的界面相同。
将TT4
视为DLL中的一个类。它的属性将通过串行通信从物理设备填充。
TT4 tt4 = new TT4();
// Some code to populate tt4 object
MessageBox.Show(tt4.SerialNumber);
tt4.SerialNumber = "123";
由于tt4
对象将代表物理设备,因此并非所有应用程序都可以修改其所有属性。这没有意义,如果我们允许,那么任何应用程序都可以更改设备的序列号。 (是的,SerialNumber可以写回设备)。
我们只有一个应用程序(例如AppA)可以设置和更改SerialNumber。其他应用程序不应该这样做。将SerialNumber的setter设为internal
并通过InternalsVisibleTo
向AppA授予权限,从而阻止了这一过程。
请注意,为库提供两个类不是解决方案。说,我已经为TT4
- TT4
(不能写SerialNumber)和TT4Super
(可以编写SerialNumber)实现了两个类。当DLL被提供给客户端时,他们仍然可以看到TT4Super
并使用它。
我不是其他应用程序的开发者,我无法控制它们。
答案 0 :(得分:2)
这样做的一种方法是将应该向AppA公开的所有成员提取到抽象类(或一般的父类)并将它们protected internal
。要从AppA访问它们,它必须从抽象类继承。例如
public abstract class ParentA
{
internal int ReallyInternal {get; set;}
protected internal int AppAInternal {get; set;}
}
AppA以下列方式访问它:
internal class AinAppA : ParentA
{
internal AinAppA()
{
this.AppAInternal = 1; // can access parents protected members
// this.ReallyInternal = 2; // but pure internal members are not visible
}
}
作为旁注,InternalsVisibleTo
并不是一个访问修饰符。它的主要目的是使单元测试更容易,不能在生产组件之间进行通信。
答案 1 :(得分:1)
您是否主要担心AppB的设计人员会对您的DLL做恶意攻击,或者您只是想阻止他们无意中做某事?如果他们愿意,让你的会员internal
真的不会通过反思来防止他人受到伤害。
您可以使用的一种(当然不是很好的)方法是将这些成员公开,但通过检查调用程序集阻止除AppA之外的任何人使用它们:
private void VerifyCaller(Assembly a)
{
if (a == Assembly.GetExecutingAssembly()) { return; }
var name = a.GetName();
if(name.Name == "AppA" && name.GetPublicKey() == appAPublicKey) { return; }
throw new InvalidOperationException("You can't access this");
}
private string _serialNumber;
public string SerialNumber
{
get { return _serialNumber; }
set
{
VerifyCaller(Assembly.GetCallingAssembly());
_serialNumber = value;
}
}
这至少应该阻止任何人轻易使用反射来规避你的防御。