Niyetinizin bazı sınırlı biçimleri, Ek Açıklamalar ve Dinamik Proxy Kalıbı (Java ve C # 'da dinamik proxy'ler için yerleşik uygulamalar mevcuttur) aracılığıyla Java ve C #' da mümkün olan bilgimdir.
Java sürümü
Ek açıklama:
@Target(ElementType.PARAMETER)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface IntRange {
int min ();
int max ();
}
Proxy örneğini oluşturan Wrapper sınıfı:
public class Wrapper {
public static Object wrap(Object obj) {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new MyInvocationHandler(obj));
}
}
Her yöntem çağrısında bypass işlevi gören 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);
}
}
Kullanım için Örnek Arayüz:
public interface Example {
public void print(@IntRange(min=0,max=100) int num);
}
Main-Yöntem:
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);
Çıktı:
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 # -Sürüm
Ek açıklama (C # olarak adlandırılan öznitelik):
[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 Alt Sınıfı:
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;
}
}
Örnek Sınıf:
public class ExampleClass
{
public void PrintNum([IntRange(0,100)] int num)
{
Console.WriteLine(num.ToString());
}
}
Kullanımı:
static void Main(string[] args)
{
dynamic myObj = new DynamicProxy(new ExampleClass());
myObj.PrintNum(99);
myObj.PrintNum(-5);
}
Sonuç olarak, Java'da çalışmak için böyle bir şey alabileceğinizi görüyorsunuz , ancak tamamen uygun değil, çünkü
- Proxy sınıfı yalnızca arabirimler için örneklendirilebilir, yani sınıfınızın bir arabirim uygulaması gerekir
- İzin Verilen Aralık yalnızca arayüz düzeyinde bildirilebilir
- Daha sonra kullanım sadece başlangıçta ekstra çaba ile gelir (MyInvocationHandler, her örneklemede sarma) ve bu da anlaşılabilirliği biraz azaltır
İçinde DynamicObject sınıfının yetenekleri C # C # uygulamasında gördüğümüz gibi, arayüz kısıtlamayı kaldırmak. Ne yazık ki, bu dinamik davranış bu durumda statik tür güvenliğini kaldırır, bu nedenle dinamik proxy'de bir yöntem çağrısına izin verilip verilmediğini belirlemek için çalışma zamanı denetimleri gereklidir.
Bu kısıtlamalar sizin için kabul edilebilirse, bu daha fazla kazma için bir temel oluşturabilir!