आपके इरादे का कुछ प्रतिबंधित रूप मेरे ज्ञान जावा और सी # में एनोटेशन और डायनेमिक प्रॉक्सी पैटर्न के संयोजन के माध्यम से संभव है (जावा और सी # में डायनेमिक प्रॉक्सी के लिए अंतर्निहित कार्यान्वयन मौजूद है)।
जावा संस्करण
एनोटेशन:
@Target(ElementType.PARAMETER)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface IntRange {
int min ();
int max ();
}
प्रॉक्सी उदाहरण बनाने वाला रैपर वर्ग:
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 # नामक विशेषता में):
[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; }
}
डायनामिकऑब्जेक्ट सब-क्लास:
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;
}
}
उदाहरण:
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);
}
अंत में, आप देखते हैं कि आप जावा में काम करने के लिए ऐसा कुछ प्राप्त कर सकते हैं , लेकिन यह पूरी तरह से सुविधाजनक नहीं है, क्योंकि
- प्रॉक्सी क्लास केवल इंटरफेस के लिए तुरंत किया जा सकता है, यानी आपकी क्लास को एक इंटरफ़ेस लागू करना होगा
- अनुमति सीमा केवल इंटरफ़ेस स्तर पर घोषित की जा सकती है
- बाद में उपयोग केवल शुरुआत में अतिरिक्त प्रयास (MyInvocationHandler, हर तात्कालिकता पर रैपिंग) के साथ आता है, जो समझने की क्षमता को भी थोड़ा कम करता है
जैसा कि आप सी # कार्यान्वयन में देखते हैं, सी # में डायनामिकऑब्जेक्ट क्लास की क्षमताएं इंटरफ़ेस प्रतिबंध को हटा देती हैं। दुर्भाग्य से, यह गतिशील व्यवहार इस मामले में स्थिर प्रकार की सुरक्षा को हटा देता है, इसलिए यह निर्धारित करने के लिए रनटाइम जांच आवश्यक है कि क्या डायनेमिक प्रॉक्सी पर एक विधि कॉल की अनुमति है।
यदि वे प्रतिबंध आपके लिए स्वीकार्य हैं, तो यह आगे की खुदाई के लिए एक आधार के रूप में काम कर सकता है!