ความตั้งใจของคุณคือความรู้ของฉันใน Java และ C # ผ่านการผสมผสานของ Annotations และ Dynamic Proxy Pattern (มีการปรับใช้ในตัวสำหรับพร็อกซีแบบไดนามิกใน Java และ C #)
รุ่น Java
คำอธิบายประกอบ:
@Target(ElementType.PARAMETER)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface IntRange {
int min ();
int max ();
}
คลาส Wrapper ที่สร้างอินสแตนซ์ Proxy:
public class Wrapper {
public static Object wrap(Object obj) {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new MyInvocationHandler(obj));
}
}
InvocationHandler ทำหน้าที่เป็นบายพาสในทุกวิธีการโทร:
public class MyInvocationHandler implements InvocationHandler {
private Object impl;
public MyInvocationHandler(Object obj) {
this.impl = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Annotation[][] parAnnotations = method.getParameterAnnotations();
Annotation[] par = null;
for (int i = 0; i<parAnnotations.length; i++) {
par = parAnnotations[i];
if (par.length > 0) {
for (Annotation anno : par) {
if (anno.annotationType() == IntRange.class) {
IntRange range = ((IntRange) anno);
if ((int)args[i] < range.min() || (int)args[i] > range.max()) {
throw new Throwable("int-Parameter "+(i+1)+" in method \""+method.getName()+"\" must be in Range ("+range.min()+","+range.max()+")");
}
}
}
}
}
return method.invoke(impl, args);
}
}
ตัวอย่างอินเทอร์เฟซสำหรับการใช้งาน:
public interface Example {
public void print(@IntRange(min=0,max=100) int num);
}
หลักวิธีการ:
Example e = new Example() {
@Override
public void print(int num) {
System.out.println(num);
}
};
e = (Example)Wrapper.wrap(e);
e.print(-1);
e.print(10);
เอาท์พุท:
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy0.print(Unknown Source)
at application.Main.main(Main.java:13)
Caused by: java.lang.Throwable: int-Parameter 1 in method "print" must be in Range (0,100)
at application.MyInvocationHandler.invoke(MyInvocationHandler.java:27)
... 2 more
C # เวอร์ชั่น
คำอธิบายประกอบ (ใน C # เรียกว่าแอตทริบิวต์):
[AttributeUsage(AttributeTargets.Parameter)]
public class IntRange : Attribute
{
public IntRange(int min, int max)
{
Min = min;
Max = max;
}
public virtual int Min { get; private set; }
public virtual int Max { get; private set; }
}
DynamicObject Sub-Class:
public class DynamicProxy : DynamicObject
{
readonly object _target;
public DynamicProxy(object target)
{
_target = target;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
TypeInfo clazz = (TypeInfo) _target.GetType();
MethodInfo method = clazz.GetDeclaredMethod(binder.Name);
ParameterInfo[] paramInfo = method.GetParameters();
for (int i = 0; i < paramInfo.Count(); i++)
{
IEnumerable<Attribute> attributes = paramInfo[i].GetCustomAttributes();
foreach (Attribute attr in attributes)
{
if (attr is IntRange)
{
IntRange range = attr as IntRange;
if ((int) args[i] < range.Min || (int) args[i] > range.Max)
throw new AccessViolationException("int-Parameter " + (i+1) + " in method \"" + method.Name + "\" must be in Range (" + range.Min + "," + range.Max + ")");
}
}
}
result = _target.GetType().InvokeMember(binder.Name, BindingFlags.InvokeMethod, null, _target, args);
return true;
}
}
TheClassClass:
public class ExampleClass
{
public void PrintNum([IntRange(0,100)] int num)
{
Console.WriteLine(num.ToString());
}
}
การใช้งาน:
static void Main(string[] args)
{
dynamic myObj = new DynamicProxy(new ExampleClass());
myObj.PrintNum(99);
myObj.PrintNum(-5);
}
โดยสรุปคุณจะเห็นว่าคุณสามารถใช้งานJavaได้ แต่มันไม่สะดวกอย่างสิ้นเชิงเพราะ
- พร็อกซีคลาสนั้นสามารถอินสแตนซ์ของอินเตอร์เฟสได้เช่นคลาสของคุณต้องใช้อินเตอร์เฟส
- อนุญาตช่วงสามารถประกาศได้เฉพาะในระดับอินเตอร์เฟซ
- การใช้งานในภายหลังมาพร้อมกับความพยายามพิเศษในการเริ่มต้น (MyInvocationHandler, การห่อทุกการสร้างอินสแตนซ์) ซึ่งยังช่วยลดความเข้าใจเล็กน้อย
ความสามารถของคลาส DynamicObject ในC #ลบข้อ จำกัด ของอินเทอร์เฟซตามที่คุณเห็นในการใช้งาน C # ขออภัยลักษณะการทำงานแบบไดนามิกนี้จะลบความปลอดภัยประเภทคงที่ในกรณีนี้ดังนั้นการตรวจสอบแบบรันไทม์จำเป็นต้องพิจารณาว่าอนุญาตให้เรียกใช้เมธอดบนไดนามิกพร็อกซีได้หรือไม่
หากข้อ จำกัด เหล่านั้นเป็นที่ยอมรับสำหรับคุณนี่จะเป็นพื้นฐานสำหรับการขุดต่อไป!