我正在寻找有效隐藏继承成员的方法。 我有一个类库,它们从通用基类继承。 一些较新的后代类继承了依赖属性,这些依赖属性已经过时,并且在使用IntelliSense或在可视设计器中使用这些类时可能会造成一些混乱。
这些类都是为WPF或Silverlight 2.0编写的所有控件。 我知道ICustomTypeDescriptor和ICustomPropertyProvider,但是我可以肯定它们不能在Silverlight中使用。
它不仅是功能性问题,还包括可用性问题。 我该怎么办?
更新资料
我真正想要隐藏的某些属性来自我自己的祖先,并且由于我正在设计特定的工具,因此无法使用new运算符进行成员隐藏。 (我知道,这很荒谬)
像上面的迈克尔建议那样覆盖它们,并且为了防止人们使用覆盖的(sp?)方法,请将它们标记为过时的:
1 2 3 4
| [Obsolete("These are not supported in this class.", true)]
public override void dontcallmeanymore()
{
} |
如果将第二个参数设置为true,则如果有人尝试调用该方法并且第一个参数中的字符串是消息,则会生成编译器错误。如果parm2为false,则仅生成编译器警告。
虽然您无法阻止使用这些继承的成员,但应该可以使用EditorBrowsableAttribute将它们从IntelliSense中隐藏:
1 2 3 4
| Using System.ComponentModel;
[EditorBrowsable(EditorBrowsableState.Never)]
private string MyHiddenString ="Muahahahahahahahaha"; |
编辑:刚刚在文档注释中看到了这一点,这使其在此目的上毫无用处:
There is a prominent note that states that this attribute"does not suppress members from a class in the same assembly". That is true but not complete. Actually, the attribute does not suppress members from a class in the same solution.
您可以做的一件事是包含对象,而不是从另一个类扩展。这将使您在暴露要公开的内容方面具有最大的灵活性,但是如果您绝对需要该对象属于该类型,则不是理想的解决方案(但是您可以从吸气剂中公开该对象)。
从而:
1 2 3 4
| public class MyClass : BaseClass
{
// Your stuff here
} |
成为:
1 2 3 4 5 6 7 8 9
| public class MyClass
{
private BaseClass baseClass;
public void ExposeThisMethod()
{
baseClass.ExposeThisMethod();
}
} |
要么:
1 2 3 4 5 6 7 8 9 10 11 12
| public class MyClass
{
private BaseClass baseClass;
public BaseClass BaseClass
{
get
{
return baseClass;
}
}
} |
我认为,最好的方法是将组合而不是继承作为考虑因素。
或者,您可以创建一个具有所需成员的接口,让派生类实现该接口,然后对该接口进行编程。
完全隐藏并标记为不使用,包括智能感应,我相信这是大多数读者期望的...
1 2 3
| [Obsolete("Not applicable in this class.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] |
我知道对此有多个答案,而且现在已经很老了,但是最简单的方法就是将它们声明为new private。
考虑我当前正在处理的一个示例,其中有一个API使第三方DLL中的每个方法都可用。我必须采用他们的方法,但是我想使用.Net属性,而不是" getThisValue"和" setThisValue"方法。因此,我构建了第二个类,继承了第一个类,创建了一个使用get和set方法的属性,然后将原始的get和set方法重写为私有。想要在其上构建其他功能的任何人仍然可以使用它们,但是如果他们只想使用我正在构建的引擎,那么他们将能够使用属性而不是方法。
使用double类方法摆脱了对无法使用new声明隐藏成员的任何限制。如果成员被标记为虚拟成员,则根本无法使用override。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class APIClass
{
private static const string DllName ="external.dll";
[DllImport(DllName)]
public extern unsafe uint external_setSomething(int x, uint y);
[DllImport(DllName)]
public extern unsafe uint external_getSomething(int x, uint* y);
public enum valueEnum
{
On = 0x01000000;
Off = 0x00000000;
OnWithOptions = 0x01010000;
OffWithOptions = 0x00010000;
}
}
public class APIUsageClass : APIClass
{
public int Identifier;
private APIClass m_internalInstance = new APIClass();
public valueEnum Something
{
get
{
unsafe
{
valueEnum y;
fixed (valueEnum* yPtr = &y)
{
m_internalInstance.external_getSomething(Identifier, yPtr);
}
return y;
}
}
set
{
m_internalInstance.external_setSomething(Identifier, value);
}
}
new private uint external_setSomething(int x, float y) { return 0; }
new private unsafe uint external_getSomething(int x, float* y) { return 0; }
} |
现在,valueEnum可用于两个类,但是在APIUsageClass类中仅可见该属性。对于想要扩展原始API或以其他方式使用它的人,仍然可以使用API??Class类,而对于想要更简单的东西的人,可以使用API??UsageClass。
最终,我要做的是将APIClass内部化,并且只公开继承的类。
我测试了所有建议的解决方案,它们并没有真正隐藏新成员。
但这确实是:
1 2 3 4 5
| [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{
get { return _myHiddenProperty; }
} |
但是在代码隐藏中仍然可以访问,因此也要添加过时的属性
1 2 3 4 5 6
| [Obsolete("This property is not supported in this class", true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new string MyHiddenProperty
{
get { return _myHiddenProperty; }
} |
尽管上面已经明确指出,在C#中无法更改继承的方法和属性的访问修饰符,但我通过使用隐式强制转换的一种"伪继承"克服了这个问题。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class A
{
int var1;
int var2;
public A(int var1, int var2)
{
this.var1 = var1;
this.var2 = var2;
}
public void Method1(int i)
{
var1 = i;
}
public int Method2()
{
return var1+var2;
}
} |
现在假设您要从class A继承class B,但是想要更改某些可访问性甚至完全更改Method1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class B
{
private A parent;
public B(int var1, int var2)
{
parent = new A(var1, var2);
}
int var1
{
get {return this.parent.var1;}
}
int var2
{
get {return this.parent.var2;}
set {this.parent.var2 = value;}
}
public Method1(int i)
{
this.parent.Method1(i*i);
}
private Method2()
{
this.parent.Method2();
}
public static implicit operator A(B b)
{
return b.parent;
}
} |
通过在末尾包含隐式强制转换,它使我们可以在需要时将B对象视为A。从A->B定义隐式强制转换也很有用。
这种方法的最大缺陷是,您需要重写要"继承"的每个方法/属性。
这种方法可能存在更多缺陷,但是我喜欢将其用作一种"伪继承"。
注意:
虽然这允许更改public属性的可访问性,但不能解决将protected属性公开的问题。
您可以使用界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public static void Main()
{
NoRemoveList<string> testList = ListFactory<string>.NewList();
testList.Add(" this is ok");
// not ok
//testList.RemoveAt(0);
}
public interface NoRemoveList< T >
{
T this[int index] { get; }
int Count { get; }
void Add(T item);
}
public class ListFactory< T >
{
private class HiddenList: List< T >, NoRemoveList< T >
{
// no access outside
}
public static NoRemoveList< T > NewList()
{
return new HiddenList();
}
} |