{"id":206,"date":"2014-12-28T02:06:43","date_gmt":"2014-12-28T00:06:43","guid":{"rendered":"http:\/\/oguzkartal.net\/blog\/?p=206"},"modified":"2021-10-31T16:05:13","modified_gmt":"2021-10-31T13:05:13","slug":"c-ve-statik-arayuz-static-interface","status":"publish","type":"post","link":"https:\/\/www.oguzkartal.net\/blog\/index.php\/2014\/12\/28\/c-ve-statik-arayuz-static-interface\/","title":{"rendered":"C# ve Statik Aray\u00fcz (Static Interface)"},"content":{"rendered":"<p>Merhaba,<\/p>\n<p>Ba\u015fl\u0131\u011f\u0131 g\u00f6ren deneyimli programc\u0131lar durumu garipseyecektir. \u00c7\u00fcnk\u00fc bilirler ki bir aray\u00fcz&#8217;\u00fcn (interface) kullan\u0131m amac\u0131 statik olmayan (non-static) bir nesne&#8217;nin (object) sa\u011flamas\u0131 zorunlu\/gerekli \u00fcye fonksiyon ve \u00f6zelliklerinin tan\u0131mlanmas\u0131 ve ilgili s\u0131n\u0131f&#8217;\u0131n (class) t\u00fcr\u00fcnden ve hiyerar\u015fisinden ba\u011f\u0131ms\u0131z kullan\u0131labilmesini ama\u00e7lar. hiyerar\u015fiden ba\u011f\u0131ms\u0131z olmas\u0131 abstract class (\u00f6zet s\u0131n\u0131f)&#8217;dan ayr\u0131lmas\u0131n\u0131 sa\u011flar.<\/p>\n<p>Aray\u00fczler bu amac\u0131 g\u00fctt\u00fc\u011f\u00fc i\u00e7in bir instance&#8217;a sahip nesneye ba\u011f\u0131ml\u0131d\u0131rlar. Ve statik s\u0131n\u0131flar herhangi bir instance&#8217;a sahip olmad\u0131klar\u0131ndan aray\u00fczlerin \u00fczerlerinde ger\u00e7eklenmesi mant\u0131ks\u0131zd\u0131r \u00e7\u00fcnk\u00fc statik s\u0131n\u0131flar\u0131n implement etti\u011fi (ger\u00e7ekledi\u011fi ) statik \u00fcyelerin hangi s\u0131n\u0131fa ait t\u00fcrden oldu\u011fu bilgisi \u00e7al\u0131\u015fma zaman\u0131nda (Runtime) yoktur. \u00c7al\u0131\u015fma zaman\u0131nda bize sunulan tek somut veri t\u00fcr\u00fcn bilgisini tutan <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.type%28v=vs.110%29.aspx\" target=\"_blank\" rel=\"noopener\">Type<\/a> s\u0131n\u0131f\u0131d\u0131r. Bu bilgiyi bir k\u00f6\u015fede tutal\u0131m birazdan yapaca\u011f\u0131m\u0131z deneysel birazc\u0131k da fantastik say\u0131labilecek \u00e7al\u0131\u015fmam\u0131zda bu bilgi bize yard\u0131m edecek. Ancak bizim yapmay\u0131 d\u00fc\u015f\u00fcnd\u00fc\u011f\u00fcm\u00fcz \u015fey bir aray\u00fcz&#8217;\u00fcn statik olarak ger\u00e7eklenip t\u00fcrden ba\u011f\u0131ms\u0131z\u00a0 ortak bir tasar\u0131m aray\u00fcz\u00fcnden eri\u015febilmek.<\/p>\n<h4>Peki Gerekli Mi?<\/h4>\n<p>Gerekli olup olmad\u0131\u011f\u0131n\u0131 bir \u00f6rnek senaryo \u00fcst\u00fcnden d\u00fc\u015f\u00fcnelim. Diyelim ki ortak bir aray\u00fcz metodlar\u0131 sa\u011flamak ve statik olmak zorunda olan bir grup s\u0131n\u0131f\u0131 handle eden bir sistem yazman\u0131z gerekiyor. Bu s\u0131n\u0131flar\u0131n her i\u015flemde s\u0131f\u0131rdan bir \u00f6rnek (instance) yaratmas\u0131n\u0131 istemiyorsunuz. \u00d6zellikle bu sistem birden \u00e7ok t\u00fcrde olabilen ancak ortak bir aray\u00fcz sa\u011flayan ve bunlar\u0131 kullanarak y\u00f6neten (manage) bir sistem. Bize her t\u00fcr i\u00e7in ayr\u0131 ayr\u0131 u\u011fra\u015ft\u0131rmayacak ortak bir aray\u00fcz laz\u0131m. Bir\u00e7ok ki\u015finin akl\u0131na \u00e7e\u015fitli \u00e7\u00f6z\u00fcmler gelebilir \u00f6rne\u011fin. \u00d6rne\u011fin kimisi s\u0131n\u0131f\u0131 statik olarak i\u015faretlemeyip ancak statik gibi davranan bir s\u0131n\u0131f\u0131 interface ile implement edip bir singleton instance arac\u0131l\u0131\u011f\u0131 ile tek bir \u00f6rnek \u00fczerinden sunmak olabilir. Ancak belirtti\u011fim gibi hem s\u0131n\u0131f\u0131m\u0131z ger\u00e7ek anlamda statik olmaktan \u00e7\u0131kacak, hem bir \u015fekilde s\u0131n\u0131f\u0131n bir adet de olsa \u00f6rne\u011fi olmu\u015f olacak hem de bize bir ortak y\u00f6netim imkan\u0131 sa\u011flamayacakt\u0131r. \u00c7\u00fcnk\u00fc singleton design pattern&#8217;de (tasar\u0131m \u00f6r\u00fcnt\u00fcs\u00fc) \u00f6rne\u011fi alabilece\u011fimiz bir statik property&#8217;e ihtiyac\u0131m\u0131z olacak ve bunu aray\u00fczler arac\u0131l\u0131\u011f\u0131 ile alma \u015fans\u0131m\u0131z yok.<\/p>\n<p>\u0130\u015fte b\u00f6yle bir senaryoda hem ortak aray\u00fcz sunan hem de bunu statik olarak destekleyen bir yap\u0131ya ihtiya\u00e7 olabiliyor.<\/p>\n<h4>Nas\u0131l?<\/h4>\n<p>\u0130htiyac\u0131 belirledi\u011fimize g\u00f6re bunu yapman\u0131n bir olas\u0131l\u0131\u011f\u0131 olup olmad\u0131\u011f\u0131 \u00fczerine konu\u015fulabilir. \u0130\u015fte burada bize runtime&#8217;da tip bilgisi sa\u011flayabilen diller istedi\u011fimizi yapabilme konusunda olduk\u00e7a yard\u0131mc\u0131 oluyor. Runtime&#8217;da t\u00fcrlere ait tek bilgimizin Type s\u0131n\u0131f\u0131 oldu\u011funu yukar\u0131da s\u00f6ylemi\u015ftim. Bu i\u015fte bu s\u0131n\u0131f\u0131 yo\u011fun olarak kullanaca\u011f\u0131z ancak k\u0131saca Type s\u0131n\u0131f\u0131 nedir, neleri sa\u011flar k\u0131saca \u00fczerinde duray\u0131m. Type s\u0131n\u0131f\u0131 .NET&#8217;de primitif t\u00fcrler de dahil olmak \u00fczere (Not: Primitif t\u00fcrler de asesen birer s\u0131n\u0131ft\u0131r ve alias edilmi\u015flerdir) t\u00fcm nesnelerin t\u00fcr bilgilerini, buna t\u00fcrle ilgili akl\u0131n\u0131za gelebilecek her t\u00fcrl\u00fc bilginin (class, struct, enum olup olmad\u0131\u011f\u0131, sa\u011flad\u0131\u011f\u0131 metodlar, propertyler, fieldlar (\u00fcye de\u011fi\u015fken), metodlar\u0131n access modifier bilgileri vs vs. liste olduk\u00e7a uzun) tutuldu\u011fu bir yap\u0131d\u0131r. Bu sayede \u00e7al\u0131\u015fma zaman\u0131 hangi nesnenin ne oldu\u011fu konusunda detayl\u0131 bilgi sahibi olunabiliyor. Ancak bu bilgi tek ba\u015f\u0131na bir\u015fey ifade etmeyecektir. Bu bilgiyi kullanabilecek bir yap\u0131n\u0131n da var olmas\u0131 gerekir ve bu yap\u0131 da zaten mevcuttur. Genel anlamda Reflection s\u00f6zc\u00fc\u011f\u00fc ile tan\u0131mlanan bu geni\u015f yap\u0131 .NET&#8217;in \u00f6nemli bir par\u00e7as\u0131d\u0131r. Reflection, CLR (Common Language Runtime) taraf\u0131ndan desteklenen ve assemblyler, t\u00fcrler \u00fczerinde dinamik olarak d\u00fczenleme ve oynama yapabilece\u011finiz bir yap\u0131 sunar. \u00d6yle ki \u00e7al\u0131\u015fma zaman\u0131 dahi bir assembly olu\u015fturup i\u00e7erisine t\u00fcrler, metodlar tan\u0131mlayabilir ve bunlar\u0131 yine runtime&#8217;da \u00e7al\u0131\u015ft\u0131rabilirsiniz. G\u00f6r\u00fcld\u00fc\u011f\u00fc gibi olduk\u00e7a esnek bir yap\u0131d\u0131r. Ancak bu i\u015flemler olduk\u00e7a maliyetli olduklar\u0131ndan her durumda kullan\u0131lmalar\u0131 tavsiye edilmez. E\u011fer bir i\u015fi dilin ve framework&#8217;\u00fcn sa\u011flad\u0131\u011f\u0131 native (yerel) \u00e7\u00f6z\u00fcmlerle yapabiliyorsan\u0131z \u00f6nce o \u015fekilde yap\u0131p, yapam\u0131yorsan\u0131z son \u00e7are olarak ba\u015fvurmak daha do\u011fru olur. Ancak \u015furas\u0131 da bir ger\u00e7ek ki bug\u00fcn bir \u00e7ok framework bu reflection \u00f6zelliklerinden yo\u011fun olarak faydalan\u0131yorlar. Buna en g\u00fc\u00e7l\u00fc \u00f6rnek ORM (Object relational mapping) frameworkleri. Bir\u00e7ok MVC framework&#8217;\u00fc de bundan faydalanabiliyor.<\/p>\n<p>Peki reflection&#8217;\u0131n bize ne gibi bir faydas\u0131 dokunabilir?<\/p>\n<p>En ba\u015fta bahsi ge\u00e7ti\u011fi gibi elimizde Type ve Reflection gibi iki ara\u00e7 var. \u0130lk olarak t\u00fcr bilgisi elimizde olan bir statik s\u0131n\u0131f\u0131n \u00fcye fonksiyonlar\u0131n\u0131 reflection arac\u0131l\u0131\u011f\u0131 ile \u00e7al\u0131\u015ft\u0131rabiliriz. Ancak i\u015f bu kadar de\u011fil. Ortak bir programlama aray\u00fcz\u00fc sistemi geli\u015ftirmemiz gerek.<\/p>\n<p>En ba\u015fta statik bir s\u0131n\u0131fa ait bir metodun \u00e7al\u0131\u015ft\u0131r\u0131lmas\u0131 ile ba\u015flayal\u0131m. Bunun i\u00e7in \u00f6nceden yazd\u0131\u011f\u0131m kodlar\u0131 par\u00e7a par\u00e7a ilgili konular\u0131n alt\u0131na koyarak devam edece\u011fim.<\/p>\n<pre class=\"font:inconsolata font-size:14 toolbar:2 lang:c# decode:true\">public static object Invoke(Type staticClassType, string function, bool isProperty, params object[] args)\r\n{\r\n    MethodInfo staticMethod=null;\r\n    Type classType = staticClassType;\r\n    object result;\r\n    BindingFlags bindFlag = BindingFlags.Static | BindingFlags.Public;\r\n\r\n    if (isProperty)\r\n    {\r\n        function = (args.Length&gt;0 ? \"set_\" : \"get_\") + function;\r\n    }\r\n\r\n\r\n    staticMethod = classType.GetMethod(function, bindFlag);\r\n\r\n    if (staticMethod == null)\r\n        throw new Exception(string.Format(\"{0} is not exists\", function));\r\n\r\n\r\n    try\r\n    {\r\n        result = staticMethod.Invoke(null, args);\r\n    }\r\n    catch (TargetInvocationException e)\r\n    {\r\n        throw e.InnerException;\r\n    }\r\n\r\n    return result;\r\n}<\/pre>\n<p>Temel olarak bir statik s\u0131n\u0131fa ait statik metod&#8217;u \u00e7a\u011f\u0131ran Invoke ad\u0131nda bir metodumuz var. 4 adet arg\u00fcmana sahip. \u0130lk olarak \u00e7a\u011fr\u0131lacak statik s\u0131n\u0131f\u0131n t\u00fcr bilgisi bu yukar\u0131da bahsetti\u011fimiz Type t\u00fcr\u00fcnden bir veri. \u0130kinci olarak metod veya property (\u00f6zellik) ad\u0131, \u00fc\u00e7\u00fcnc\u00fc olarak metodun bir \u00f6zellik mi yoksa metod mu oldu\u011fu ve e\u011fer arg\u00fcman alan bir fonksiyonsa arg\u00fcman listesi.<\/p>\n<p>Bu yard\u0131mc\u0131 fonksiyon \u00f6ncelikle metodun bir property olup olmad\u0131\u011f\u0131 bilgisinden ve arg\u00fcman al\u0131p almad\u0131\u011f\u0131 bilgisinden yola \u00e7\u0131karak propertynin internal (i\u00e7sel) getter veya setter metodu i\u00e7in \u00f6nek vererek haz\u0131rlan\u0131yor. Ard\u0131ndan istedi\u011fimiz metoda ait MethodInfo bilgisini almak i\u00e7in t\u00fcr s\u0131n\u0131f nesnesine ait GetMethod&#8217;u kullan\u0131yoruz. Burada bilinmesi gereken nokta bir BindingFlags de\u011feri almas\u0131.<\/p>\n<p><span class=\"font:inconsolata font-size:14 toolbar:2 lang:c# decode:true crayon-inline\">BindingFlags bindFlag = BindingFlags.Static | BindingFlags.Public;<\/span><\/p>\n<p>Bu de\u011fer bize metoda ili\u015fkin hangi \u00f6znitelik bilgilerine sahip bilgilerin getirilece\u011fini belirtir. Bu sayede t\u00fcm metod veya metodlar yerine sadece istedi\u011fimiz t\u00fcrden metodlar\u0131 almam\u0131z\u0131 sa\u011flar. Biz hem public access modifiers&#8217;a (Eri\u015fim Niteleyici) hem de statik olarak implement edilmi\u015f belirtti\u011fimiz isme sahip metodu istedi\u011fimizi belirtiyoruz. Ard\u0131ndan metod bilgisini sunan nesneyi Invoke \u00e7a\u011fr\u0131s\u0131 ile \u00e7a\u011f\u0131r\u0131yoruz. \u0130lk arg\u00fcman \u00e7a\u011fr\u0131lacak nesneyi ald\u0131\u011f\u0131 i\u00e7in statik fonksiyonlar i\u00e7in bu de\u011fer null olmal\u0131d\u0131r.<\/p>\n<p>Temel olarak i\u015fi yapan k\u0131s\u0131m bu metod ve di\u011fer k\u0131s\u0131mlar\u0131 bunun \u00fczerine in\u015fa edece\u011fiz. Harici olarak bu fonksiyona destekleyici 2 fonksiyon daha ekleyelim.<\/p>\n<pre class=\"lang:c# decode:true \">public static E Invoke&lt;T, E&gt;(string function, bool isProperty, params object[] args)\r\n{\r\n    return Invoke&lt;E&gt;(typeof(T), function, isProperty, args);\r\n}\r\n\r\npublic static E Invoke&lt;E&gt;(Type staticClassType, string function, bool isProperty, params object[] args)\r\n{\r\n    return (E)Invoke(staticClassType, function, isProperty, args);\r\n}<\/pre>\n<p>Bu fonksiyonlar bize kolayl\u0131k sa\u011flama ama\u00e7l\u0131 olacak.<\/p>\n<p><span style=\"color: #c91818;\"><strong>Problem #1: <\/strong><\/span><strong>Statik s\u0131n\u0131f\u0131n, statik olarak aray\u00fcz\u00fc ger\u00e7ekledi\u011fine (implementation) nas\u0131l g\u00fcvenece\u011fiz? Bunun i\u00e7in bir kontrol yok mu?<\/strong><\/p>\n<p>Bu \u00f6nemi olan bir sorun. \u00c7\u00fcnk\u00fc bize verilen bir t\u00fcr\u00fcn ger\u00e7ekten tam olarak aray\u00fcz\u00fc eksiksik ger\u00e7eklemesi gerek ve bizim bunu biliyor olmam\u0131z laz\u0131m. Bu y\u00fczden bize bunu denetleyen bir yard\u0131mc\u0131 gerekiyor. Ve bunun i\u00e7in ReflectionHelper ad\u0131nda bir yard\u0131mc\u0131 s\u0131n\u0131f yazarak bu i\u015fi halledelim.<\/p>\n<pre class=\"lang:c# decode:true\">static class ReflectionHelper\r\n{\r\n    private static bool _HasMethod(Type classType, string method, bool tStatic, bool tPrivate)\r\n    {\r\n        MethodInfo methInfo;\r\n        BindingFlags bindFlags = BindingFlags.Default;\r\n\r\n        if (tStatic)\r\n            bindFlags |= BindingFlags.Static;\r\n\r\n        bindFlags |= tPrivate ? BindingFlags.NonPublic : BindingFlags.Public;\r\n\r\n        methInfo = classType.GetMethod(method, bindFlags);\r\n\r\n        if (methInfo == null)\r\n            return false;\r\n\r\n        return true;\r\n    }\r\n\r\n    public static bool HasStaticMethod(Type classType, string method, bool isPrivate)\r\n    {\r\n        return _HasMethod(classType, method, true, isPrivate);\r\n    }\r\n\r\n    public static bool ImplementsOfStaticInterface&lt;T&gt;(Type interfaceType, bool throwExceptionOnMismatch)\r\n    {\r\n        return ImplementsOfStaticInterface(typeof(T), interfaceType, throwExceptionOnMismatch);\r\n    }\r\n\r\n    public static bool ImplementsOfStaticInterface(Type classType, Type interfaceType, bool throwExceptionOnMismatch)\r\n    {\r\n        Type baseType = interfaceType;\r\n\r\n        MethodInfo[] methods;\r\n\r\n        Type[] ifaces;\r\n\r\n        if (!baseType.IsInterface)\r\n            throw new Exception(baseType.Name + \" is not an interface\");\r\n\r\n        ifaces = classType.GetInterfaces();\r\n\r\n        foreach (Type iface in ifaces)\r\n        {\r\n            if (iface == baseType)\r\n                throw new Exception(classType.Name + \" implemented as non-static object\");\r\n        }\r\n\r\n        methods = baseType.GetMethods();\r\n\r\n        foreach (MethodInfo meth in methods)\r\n        {\r\n            if (!HasStaticMethod(classType, meth.Name, false))\r\n            {\r\n                if (throwExceptionOnMismatch)\r\n                    throw new Exception(meth.Name + \" is missing. The method not implemented as static\");\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n\r\n        methods = null;\r\n        ifaces = null;\r\n\r\n        return true;\r\n\r\n    }\r\n}<\/pre>\n<p>Yard\u0131mc\u0131 s\u0131n\u0131f\u0131ndaki <span class=\"lang:c# decode:true  crayon-inline\">ImplementsOfStaticInterface<\/span> metodu bahsi ge\u00e7en probleme \u00e7\u00f6z\u00fcm getirecek. Temel olarak yapt\u0131\u011f\u0131 i\u015f \u015fu. Fonksiyona bir t\u00fcr ve kontrol edilecek aray\u00fcz t\u00fcr bilgisi ile \u00f6nce kontrol edilecek t\u00fcre ait aray\u00fczleri al\u0131p kontrol etti\u011fimiz aray\u00fcz tipi olup olmad\u0131\u011f\u0131na bakmak. E\u011fer varsa t\u00fcr standart \u015fekilde implement edilmi\u015f. E\u011fer bu k\u0131s\u0131m tamam ise t\u00fcre ait t\u00fcm metodlar\u0131 alarak statik s\u0131n\u0131fta bu metodlar\u0131n hem public hem de statik olarak ger\u00e7eklendi\u011fini kontrol ediliyor. Bu a\u015famadan s\u0131n\u0131flar aray\u00fcz\u00fcn tam olarak statik ger\u00e7eklendi\u011fini garantilemi\u015f oluyor.<\/p>\n<p>Ek olarak statik metod \u00e7a\u011fr\u0131s\u0131 yapan StaticMethodInvoker s\u0131n\u0131f\u0131m\u0131za biraz daha k\u0131saltmak i\u00e7in iki ek fonksiyon ekleyelim.<\/p>\n<pre class=\"lang:c# decode:true\">public static bool ImplementsOf&lt;T&gt;(Type t)\r\n{\r\n    return ReflectionHelper.ImplementsOfStaticInterface&lt;T&gt;(t, false);\r\n}\r\n\r\npublic static bool ImplementsOf(Type classType, Type interfaceType)\r\n{\r\n    return ReflectionHelper.ImplementsOfStaticInterface(classType, interfaceType, false);\r\n}<\/pre>\n<p>b\u00f6ylece kontrol etmek istedi\u011fimiz X statik class&#8217;\u0131 i\u00e7in Ix aray\u00fcz\u00fc kontrol\u00fc i\u00e7in<\/p>\n<p><span class=\"lang:c# decode:true crayon-inline\">ReflectionHelper.ImplementsOf&lt;X&gt;(typeof(Ix));<\/span><\/p>\n<p><span class=\"lang:c# decode:true  crayon-inline \">ReflectionHelper.ImplementsOf(typeof(X),typeof(Ix));<\/span><\/p>\n<p>\u015feklinde kontrol edilebilir.<\/p>\n<p>\u015eimdi buraya kadar yapt\u0131klar\u0131m\u0131z\u0131 bir \u00e7al\u0131\u015ft\u0131ral\u0131m ne durumda. Bunun i\u00e7in 3 adet statik test s\u0131n\u0131f\u0131 haz\u0131rlad\u0131m. \u00d6ncesinde implementasyonu yap\u0131lacak bir de aray\u00fcz olu\u015ftural\u0131m.<\/p>\n<p>Aray\u00fcz;<\/p>\n<pre class=\"lang:c# decode:true \">interface IStaticInterfaceTemplate\r\n{\r\n    void MyMethod();\r\n    string MyMethodWithArgs(string sval);\r\n\r\n    double MyProperty\r\n    {\r\n        get;\r\n    }\r\n}<\/pre>\n<p>Test s\u0131n\u0131flar\u0131;<\/p>\n<pre class=\"lang:c# decode:true \">static class StaticImplementationAlpha\r\n{\r\n    public static void MyMethod()\r\n    {\r\n        _Console.PrintLine(\"MyMethod called from Alpha class\");\r\n    }\r\n\r\n    public static string MyMethodWithArgs(string sval)\r\n    {\r\n        _Console.PrintLine(\"MyMethodWithArgs called from Alpha class. Result: \" + sval);\r\n        return sval;\r\n    }\r\n\r\n    public static double MyProperty\r\n    {\r\n        get\r\n        {\r\n            return 18.5;\r\n        }\r\n    }\r\n}\r\n\r\n\r\nstatic class StaticImplementationBeta\r\n{\r\n    public static void MyMethod()\r\n    {\r\n        _Console.PrintLine(\"MyMethod called from Beta class\");\r\n    }\r\n\r\n    public static string MyMethodWithArgs(string sval)\r\n    {\r\n        _Console.PrintLine(\"MyMethodWithArgs called from Beta class. Result: \" + sval);\r\n        return sval;\r\n    }\r\n\r\n    public static double MyProperty\r\n    {\r\n        get\r\n        {\r\n            return 10.8;\r\n        }\r\n    }\r\n}\r\n\r\nstatic class StaticImplementationThetaMissing\r\n{\r\n    public static void MyMethod()\r\n    {\r\n        _Console.PrintLine(\"MyMethod called from Theta class\");\r\n    }\r\n\r\n    public static double MyProperty\r\n    {\r\n        get\r\n        {\r\n            return 12.5;\r\n        }\r\n    }\r\n}<\/pre>\n<p>3 adet Alpha, Beta ve Theta s\u0131n\u0131flar\u0131 mevcut. Bunlardan 2 tanesi tam olarak aray\u00fcz\u00fc ger\u00e7eklerken, 1 tanesi eksik olarak ger\u00e7eklemi\u015f. MyMethodWithArgs fonksiyonu eksik. Bir adet test kodu yazal\u0131m ve sonucu g\u00f6relim.<\/p>\n<p>Test kodumuz a\u015fa\u011f\u0131da<\/p>\n<pre class=\"lang:c# decode:true \">static IEnumerable&lt;Type&gt; staticClasses;\r\nstatic List&lt;Type&gt; validClasses = new List&lt;Type&gt;();\r\n\r\nstatic IEnumerable&lt;Type&gt; GetStaticClasses()\r\n{\r\n    yield return typeof(StaticImplementationAlpha);\r\n    yield return typeof(StaticImplementationBeta);\r\n    yield return typeof(StaticImplementationThetaMissing);\r\n}\r\n\r\n\r\nstatic void ImplementationCheck()\r\n{\r\n    bool valid;\r\n    bool throwOnFail = true;\r\n\r\n    staticClasses = GetStaticClasses();\r\n    Type checkType = typeof(IStaticInterfaceTemplate);\r\n\r\n    Console.WriteLine(\"Checking implementation for \" + checkType.Name);\r\n\r\n    foreach (Type t in staticClasses)\r\n    {\r\n        try\r\n        {\r\n            valid = StaticClassInvoker.ImplementsOf(t, checkType, throwOnFail);\r\n\r\n            if (valid)\r\n                validClasses.Add(t);\r\n\r\n            Console.WriteLine(string.Format(\"{0} -&gt; Fully Implemented as Static: {1}\",\r\n                t.Name, valid.ToString()));\r\n        }\r\n        catch (Exception e)\r\n        {\r\n            Console.WriteLine(\"Exception: \" + e.Message);\r\n        }\r\n    }\r\n}<\/pre>\n<p>test kodumuz i\u00e7in yard\u0131mc\u0131 s\u0131n\u0131ftan \u00e7a\u011fr\u0131lan k\u0131sa olmas\u0131 i\u00e7in kullan\u0131lan ImplementsOf metod grubuna bir tane de ba\u015far\u0131s\u0131zl\u0131k durumunda exception f\u0131rlatmas\u0131n\u0131 belirten bir opsiyon ekledim ki ba\u015far\u0131s\u0131zl\u0131k durumu net g\u00f6r\u00fclebilsin. Kodu \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131m\u0131zda sonucumuz \u015f\u00f6yle.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-228\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/1.jpg\" alt=\"1\" width=\"550\" height=\"354\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/1.jpg 832w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/1-300x193.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><\/p>\n<p>Test kodu \u00e7al\u0131\u015ft\u0131 ve eksik olan s\u0131n\u0131f i\u00e7in ba\u015far\u0131s\u0131z olup bir exception \u00fcretti. Exception i\u00e7eri\u011finden de hangi metodun eksik oldu\u011fu bilgisini alabiliyoruz. Test kodu runtime&#8217;da bilmeyece\u011fimiz \u015fekilde 3 adet statik s\u0131n\u0131f t\u00fcr\u00fcn\u00fc bir Enumerable listesi i\u00e7ine alarak \u00e7al\u0131\u015facak. Yani tam istedi\u011fimiz gibi sadece tip bilgisine dayal\u0131 \u00e7al\u0131\u015faca\u011f\u0131z. B\u00f6ylece bilmedi\u011fimiz statik s\u0131n\u0131flar\u0131n aray\u00fcze uygun olup olmad\u0131\u011f\u0131n\u0131 biliyor olaca\u011f\u0131z. Test kodu \u00e7al\u0131\u015ft\u0131ktan sonra ge\u00e7erli olanlar\u0131 ge\u00e7erli s\u0131n\u0131flar\u0131n tutuldu\u011fu listeye al\u0131yor. Bu sonraki test kodu a\u015famas\u0131 i\u00e7in gerekli. Sonraki test metodlar\u0131n istedi\u011fimiz gibi \u00e7a\u011fr\u0131l\u0131p \u00e7a\u011fr\u0131lmad\u0131\u011f\u0131. Sonraki test i\u00e7in kodumuz \u015f\u00f6yle;<\/p>\n<pre class=\"lang:c# decode:true\">static void InvokeMember(Type t, string member, bool isProp, params object[] args)\r\n{\r\n    StaticClassInvoker.Invoke(t, member, isProp, args);\r\n}\r\n\r\nstatic void StaticImplementationInvoke()\r\n{\r\n    foreach (Type t in validClasses)\r\n    {\r\n        Console.WriteLine();\r\n        Console.WriteLine();\r\n        Console.WriteLine(\"Invoking static members of \" + t.Name);\r\n\r\n        InvokeMember(t, \"MyMethod\", false);\r\n        InvokeMember(t, \"MyMethodWithArgs\", false, \"Test\");\r\n        InvokeMember(t, \"MyProperty\", true);\r\n    }\r\n\r\n    Console.WriteLine();\r\n}<\/pre>\n<p>InvokeMember kodu k\u0131saca yard\u0131mc\u0131 olmas\u0131 i\u00e7in yaz\u0131ld\u0131. Esas olarak i\u015f<\/p>\n<p><span class=\"lang:c# decode:true  crayon-inline \">StaticClassInvoker.Invoke<\/span><\/p>\n<p>metodu kullan\u0131larak yap\u0131l\u0131yor. Metod ad\u0131 property olup olmad\u0131\u011f\u0131 ve varsa ald\u0131\u011f\u0131 arg\u00fcmanlar.<\/p>\n<p>Kodu \u00e7al\u0131\u015ft\u0131rd\u0131ktan sonra t\u00fcrden ba\u011f\u0131ms\u0131z ortak bir \u015fekilde aray\u00fczden ger\u00e7eklenmi\u015f metodlar\u0131n \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 g\u00f6rebiliriz.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/2.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-230\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/2.jpg\" alt=\"2\" width=\"550\" height=\"354\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/2.jpg 832w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/2-300x193.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><\/p>\n<p>Peki s\u0131kl\u0131kla yaz\u0131p \u00e7a\u011f\u0131rmam\u0131z gereken heryerde uzun uzun StaticClassInvoker.Invoke metodunu mu \u00e7a\u011f\u0131raca\u011f\u0131z. Biraz daha k\u0131salt\u0131c\u0131 bir\u015fey yap\u0131lamaz m\u0131?<\/p>\n<p>San\u0131r\u0131m biraz daha k\u0131saltabiliriz. Burada yapmam\u0131z gereken \u015fey bir adet proxy class (vekil s\u0131n\u0131f) haz\u0131rlamak. Ad\u0131ndan anla\u015f\u0131labilece\u011fi gibi bu \u00e7a\u011fr\u0131lar\u0131m\u0131za vekalet edecek bir s\u0131n\u0131f. \u00d6nceden hat\u0131rlayal\u0131m aray\u00fcz\u00fcm\u00fcz <span class=\"lang:c# decode:true  crayon-inline\">interface IStaticInterfaceTemplate<\/span> idi.<\/p>\n<p>Bu aray\u00fcz i\u00e7in de IStaticInterfaceProxy ad\u0131nda bir proxy class yaratal\u0131m.<\/p>\n<pre class=\"lang:c# decode:true \">public class IStaticInterfaceProxy : IStaticInterfaceTemplate\r\n{\r\nprivate Type classType;\r\n\r\npublic static explicit operator IStaticInterfaceProxy(Type type)\r\n{\r\n    return new IStaticInterfaceProxy() { classType = type };\r\n}\r\n\r\npublic void MyMethod()\r\n{\r\n    StaticClassInvoker.Invoke(this.classType, \"MyMethod\", false);\r\n}\r\n\r\npublic string MyMethodWithArgs(string sval)\r\n{\r\n    return StaticClassInvoker.Invoke&lt;string&gt;(this.classType, \"MyMethodWithArgs\", false, sval);\r\n}\r\n\r\npublic double MyProperty\r\n{\r\n    get\r\n    {\r\n        return StaticClassInvoker.Invoke&lt;double&gt;(this.classType, \"MyProperty\", true);\r\n    }\r\n}\r\n}<\/pre>\n<p>burada yapt\u0131\u011f\u0131m\u0131z aray\u00fcz\u00fc standart \u015fekilde implement eden bir s\u0131n\u0131f. Burada kilit nokta \u015fu;<\/p>\n<p>E\u011fer biz bu s\u0131n\u0131f i\u00e7in bir explicit operat\u00f6r override edip cast (tip d\u00f6n\u00fc\u015f\u00fcm) ederek bunu kontrol edersek bu proxy class&#8217;tan tip bilgisini verip do\u011frudan metodlar\u0131 \u00e7a\u011f\u0131rabiliriz. explicit keyword&#8217;\u00fc bir tipten kendi veri tipimize d\u00f6n\u00fc\u015f\u00fcmlerde kullan\u0131lan bir keyword olarak kullan\u0131l\u0131r. Bir de implicit olarak e\u015fleni\u011fi vard\u0131r ki bu da cast etmekten ziyade do\u011frudan = (e\u015fitle) operat\u00f6r\u00fc ile atanacak veriler i\u00e7indir. Yani<\/p>\n<pre class=\"lang:c# decode:true\">MyInt mn;\r\nint n = 12;\r\n\r\nmn = (MyInt)n; \/\/explicit\r\nmn = n; \/\/implicit<\/pre>\n<p>olarak i\u015flem g\u00f6r\u00fcr. Biz Type t\u00fcr\u00fcnden bir bilgiyi kendi proxy s\u0131n\u0131f\u0131m\u0131z i\u00e7in \u00e7evirece\u011fimizden<\/p>\n<p><span class=\"lang:c# decode:true  crayon-inline\">public static explicit operator IStaticInterfaceProxy(Type type)<\/span><\/p>\n<p>\u015feklinde yapt\u0131k. Bu sayede \u015fu \u015fekilde \u00e7a\u011fr\u0131 yapmam\u0131z olas\u0131.<\/p>\n<p><span class=\"lang:c# decode:true  crayon-inline\">((ProxyInterface)TypeVar).MemberFunction();<\/span><\/p>\n<p>yani t\u00fcr de\u011fi\u015fkenini proxy s\u0131n\u0131fa cast edip \u00e7a\u011f\u0131r\u0131yoruz. Bu durumda test kodumuz \u015fu hale d\u00f6n\u00fc\u015febilir<\/p>\n<pre class=\"lang:c# decode:true \">foreach (Type t in validClasses)\r\n{\r\n    ((IStaticInterfaceProxy)t).MyMethod();\r\n    ((IStaticInterfaceProxy)t).MyMethodWithArgs(\"TEST\");\r\n    ((IStaticInterfaceProxy)t).MyPropery;\r\n}<\/pre>\n<h4>\u00a0Performans?<\/h4>\n<p>B\u00fct\u00fcn bunlardan sonra ortaya bir de performans meselesi \u00e7\u0131k\u0131yor. En ba\u015fta \u015funu \u00e7ok rahat s\u00f6yleyebiliriz. Bu i\u015flem native \u015fekle g\u00f6re elbette olduk\u00e7a yava\u015f \u00e7al\u0131\u015facakt\u0131r. \u00c7\u00fcnk\u00fc en ba\u015fta da dedi\u011fim gibi reflection maliyetli bir i\u015flemdir. Ancak yava\u015ftan kas\u0131t saniyeler \u00f6l\u00e7e\u011finde de\u011fil milisaniyeler \u00f6l\u00e7e\u011findedir. Ve normal \u015fartlarda kullan\u0131ld\u0131\u011f\u0131nda aradaki performans fark\u0131 bir insan\u0131n anlayabilece\u011fi \u00f6l\u00e7ekte de\u011fildir. Performans fark\u0131 ancak milisaniye hatta mikrosaniye hassasiyetinde yap\u0131ld\u0131\u011f\u0131nda g\u00f6r\u00fclebilir. Bu sayede performans fark\u0131n\u0131n y\u00fczde de\u011ferini \u00e7\u0131kar\u0131p az \u00e7ok bir fikir sahibi olabiliriz.<\/p>\n<p>Performans \u00f6l\u00e7\u00fcm\u00fc i\u00e7in standart bir non-static aray\u00fcz implementasyonu \u00e7al\u0131\u015ft\u0131ran bir de static aray\u00fcz implementasyonu \u00e7al\u0131\u015ft\u0131ran iki farkl\u0131 test yaz\u0131p sonu\u00e7lara bakal\u0131m.<\/p>\n<p>Standart Interface Implementasyonu<\/p>\n<pre class=\"lang:c# decode:true\">class TestNativeNonStaticInterface : PerformanceTest\r\n{\r\n    private IStaticInterfaceTemplate[] impls =\r\n        new IStaticInterfaceTemplate[] \r\n            { \r\n                new NativeImplementationAlpha(), \r\n                new NativeImplementationBeta() \r\n            };\r\n\r\n\r\n    public override void Execute()\r\n    {\r\n\r\n        Begin();\r\n\r\n        for (int i = 0; i &lt; 10000; i++)\r\n        {\r\n            foreach (IStaticInterfaceTemplate iface in this.impls)\r\n            {\r\n                iface.MyMethod();\r\n                iface.MyMethodWithArgs(\"TEST\");\r\n            }\r\n        }\r\n\r\n        End();\r\n\r\n    }\r\n}\r\n<\/pre>\n<p>Statik Aray\u00fcz Implementasyonu<\/p>\n<pre class=\"lang:c# decode:true \">class TestStaticInterface : PerformanceTest\r\n{\r\n    Type[] staticClasess = new Type[]\r\n        {\r\n            typeof(StaticImplementationAlpha),\r\n            typeof(StaticImplementationBeta)\r\n        };\r\n\r\n    public override void Execute()\r\n    {\r\n        Begin();\r\n\r\n        for (int i = 0; i &lt; 10000; i++)\r\n        {\r\n            foreach (Type t in this.staticClasess)\r\n            {\r\n                StaticClassInvoker.Invoke(t, \"MyMethod\", false);\r\n                StaticClassInvoker.Invoke(t, \"MyMethodWithArgs\", false, \"TEST\");\r\n            }\r\n        }\r\n\r\n        End();\r\n    }\r\n}<\/pre>\n<p>10,000 iterasyondan olu\u015fan iki adet test mevcut. Testi \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131m\u0131zda aradaki fark\u0131 g\u00f6rebiliriz.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/31.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-238\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/31.jpg\" alt=\"_3\" width=\"550\" height=\"354\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/31.jpg 832w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/31-300x193.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><\/p>\n<p>Non-Static hali beklendi\u011fi gibi \u00e7ok h\u0131zl\u0131. 10,000 iterasyon Sadece 2 milisaniye. Statik hali ise araya bir reflection operasyonlar\u0131 girdi\u011fi i\u00e7in haliyle di\u011ferine g\u00f6re olduk\u00e7a yava\u015f. 136 milisaniye. Ancak tek ba\u015f\u0131na ele al\u0131nd\u0131\u011f\u0131nda ise yine de olduk\u00e7a makul bir s\u00fcre, yar\u0131m saniyeden daha k\u0131sa s\u00fcrd\u00fc.<\/p>\n<p>Peki bunu biraz daha k\u0131saltabilir miyiz? Belki birazc\u0131k ek i\u015flemlerle bir miktar daha k\u0131salabilir. \u00d6rne\u011fin her defas\u0131nda metod bilgilerini ba\u015ftan almak yerine tip bilgilerini \u00f6nbellekleme (caching) yaparak invoke ettirebiliriz. Peki hem in memory caching (hafizada \u00f6nbellekleme), hem de g\u00f6rece h\u0131zl\u0131 bir \u00e7\u00f6z\u00fcm ne olabilir? Bu verileri bir hashtable \u00fczerinde tutarak. Hashtable&#8217;lar ad\u0131 \u00fczerinde bir nesne veya de\u011ferin bir key (anahtar) de\u011ferinin belirli bir hash fonksiyonundan ge\u00e7irilip hashtable dizisinin uzunlu\u011funa modlanarak bir indeks elde etme i\u015flemidir temel olarak. B\u00f6ylece linear search (do\u011frusal arama) yaparak veya bir tree (a\u011fa\u00e7) \u00fczerinde arama yapmaktan k\u0131sa s\u00fcrede istenilen veriye ula\u015f\u0131labilir. B\u00f6yle bir i\u015flemin maliyeti Big-O notation g\u00f6sterimine g\u00f6re O(1) kadard\u0131r. Yani tek seferde sonuca ula\u015f\u0131r\u0131z. B\u00f6yle bir i\u015flem de bizim i\u00e7in ideal. Ancak ne kadar fayda sa\u011flayaca\u011f\u0131 me\u00e7hul. Bunu g\u00f6rece\u011fiz.<\/p>\n<pre class=\"lang:c# decode:true \">private static MethodInfo TryGetFromCache(Type keyType, string method)\r\n{\r\n    Hashtable methCacheHt;\r\n    TypeCacheInfo cacheInfo;\r\n\r\n    methCacheHt = (Hashtable)typeCacheHt[keyType];\r\n\r\n    if (methCacheHt == null)\r\n        return null;\r\n\r\n    cacheInfo = (TypeCacheInfo)methCacheHt[method];\r\n\r\n    if (cacheInfo == null)\r\n        return null;\r\n\r\n    return cacheInfo.meth;\r\n}\r\n\r\nprivate static void CacheTestAndSet(Type keyType, MethodInfo meth, BindingFlags bindFlag)\r\n{\r\n    Hashtable methodCacheHt;\r\n\r\n    if (!typeCacheHt.ContainsKey(keyType))\r\n    {\r\n        methodCacheHt = new Hashtable();\r\n        methodCacheHt.Add(meth.Name, new TypeCacheInfo() { meth = meth, bindFlag = bindFlag });\r\n        typeCacheHt.Add(keyType, methodCacheHt);\r\n    }\r\n    else\r\n        methodCacheHt = (Hashtable)typeCacheHt[keyType];\r\n\r\n    if (!methodCacheHt.ContainsKey(meth.Name))\r\n        methodCacheHt.Add(meth.Name, new TypeCacheInfo() { meth = meth, bindFlag = bindFlag });\r\n\r\n}<\/pre>\n<p>StaticClassInvoker s\u0131n\u0131f\u0131m\u0131za ek iki adet metod ekliyoruz. Birisi istenen metodun cache&#8217;den varsa okunmas\u0131n\u0131, di\u011feri ise yoksa cache&#8217;lenmesini sa\u011flayan fonksiyonlar. Esas Invoke kodu \u00fczerinde caching rutinlerini ekledikten sonra bir de caching enabled halde \u00e7al\u0131\u015fan hali i\u00e7in bir test yaz\u0131p \u00e7al\u0131\u015ft\u0131ral\u0131m.<\/p>\n<p><a href=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/4.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-236\" src=\"http:\/\/oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/4.jpg\" alt=\"4\" width=\"550\" height=\"354\" srcset=\"https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/4.jpg 832w, https:\/\/www.oguzkartal.net\/blog\/wp-content\/uploads\/2014\/12\/4-300x193.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><\/p>\n<p>\u0130\u015flem sonunda g\u00f6r\u00fcl\u00fcyor ki sadece ~20 milisaniye kadar bir kazanc\u0131m\u0131z oldu. Buradan .NET&#8217;in veya dolayl\u0131 olarak CLR&#8217;\u0131n i\u00e7sel olarak da bir caching mekanizmas\u0131 kulland\u0131\u011f\u0131 s\u00f6ylenebilir. Ama yine de bu tip bir yakla\u015f\u0131m\u0131n ne kadar performansa etki edece\u011fini g\u00f6rmek a\u00e7\u0131s\u0131ndan biraz faydal\u0131 oldu. Bu konuyla alakal\u0131 t\u00fcm kodlar, testlere <a href=\"https:\/\/github.com\/0ffffffffh\/staticinterface\">https:\/\/github.com\/0ffffffffh\/staticinterface<\/a> github adresimden ula\u015fabilirsiniz.<\/p>\n<p>Kodlar\u0131 istedi\u011finiz gibi kullanabilir, da\u011f\u0131tabilir, \u00fczerinde de\u011fi\u015fiklik yapabilirsiniz. Umar\u0131m konu ile alakas\u0131 olsun veya olmas\u0131n dolayl\u0131 olarak da olsa baz\u0131 konularda fayda sa\u011flam\u0131\u015ft\u0131r.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Merhaba, Ba\u015fl\u0131\u011f\u0131 g\u00f6ren deneyimli programc\u0131lar durumu garipseyecektir. \u00c7\u00fcnk\u00fc bilirler ki bir aray\u00fcz&#8217;\u00fcn (interface) kullan\u0131m amac\u0131 statik olmayan (non-static) bir nesne&#8217;nin (object) sa\u011flamas\u0131 zorunlu\/gerekli \u00fcye fonksiyon ve \u00f6zelliklerinin tan\u0131mlanmas\u0131 ve ilgili s\u0131n\u0131f&#8217;\u0131n (class) t\u00fcr\u00fcnden ve hiyerar\u015fisinden ba\u011f\u0131ms\u0131z kullan\u0131labilmesini ama\u00e7lar. hiyerar\u015fiden ba\u011f\u0131ms\u0131z olmas\u0131 abstract class (\u00f6zet s\u0131n\u0131f)&#8217;dan ayr\u0131lmas\u0131n\u0131 sa\u011flar. Aray\u00fczler bu amac\u0131 g\u00fctt\u00fc\u011f\u00fc i\u00e7in bir instance&#8217;a sahip&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"twitterCardType":"","cardImageID":0,"cardImage":"","cardTitle":"","cardDesc":"","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":"","footnotes":""},"categories":[71,64],"tags":[],"class_list":["post-206","post","type-post","status-publish","format-standard","hentry","category-experiment","category-programming"],"_links":{"self":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts\/206","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=206"}],"version-history":[{"count":36,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts\/206\/revisions"}],"predecessor-version":[{"id":920,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/posts\/206\/revisions\/920"}],"wp:attachment":[{"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.oguzkartal.net\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}