আমি কোনও ব্যক্তিগত পদ্ধতিতে অনুরোধ করার জন্য প্রতিবিম্বটি কীভাবে ব্যবহার করব?


326

আমার ক্লাসে ব্যক্তিগত গোষ্ঠীগুলির একটি গ্রুপ রয়েছে এবং আমাকে একটি ইনপুট মানের উপর ভিত্তি করে গতিশীল কল করতে হবে। দাওয়াতকারী কোড এবং লক্ষ্য পদ্ধতি উভয়ই একই উদাহরণে। কোডটি এর মতো দেখাচ্ছে:

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });

এই ক্ষেত্রে, GetMethod()ব্যক্তিগত পদ্ধতি ফেরত দেবে না। আমাকে কী BindingFlagsসরবরাহ করতে হবে GetMethod()যাতে এটি ব্যক্তিগত পদ্ধতিগুলি সনাক্ত করতে পারে?

উত্তর:


498

বাইন্ডিংফ্লাগগুলি গ্রহণ করে এর ওভারলোড হওয়া সংস্করণটিGetMethod ব্যবহার করার জন্য কেবল আপনার কোডটি পরিবর্তন করুন :

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, 
    BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });

এখানে বাইন্ডিংফ্ল্যাজগুলি গণনার ডকুমেন্টেশন রয়েছে


248
আমি এ নিয়ে নিজেকে এত সমস্যায় ফেলতে যাচ্ছি।
ফ্র্যাঙ্ক শ্যুইটারম্যান

1
BindingFlags.NonPublicprivateপদ্ধতিটি ফিরছে না .. :(
মৌমিত করুন

4
@ মৌমিতমন্ডল আপনার পদ্ধতিগুলি কি স্থির? আপনি নির্দিষ্ট করতে হবে BindingFlags.Instanceএবং সেইসাথে BindingFlags.NonPublicঅ স্ট্যাটিক পদ্ধতিগুলির জন্য।
ব্রায়ানস

না @ ব্রায়ানস .. পদ্ধতিটি non-staticএবং privateক্লাসটি উত্তরাধিকার সূত্রে পেয়েছে System.Web.UI.Page.. এটি আমাকে যাইহোক বোকা
বানিয়ে তোলে

3
যোগ করা BindingFlags.FlattenHierarchyআপনাকে অভিভাবক শ্রেণি থেকে আপনার দৃষ্টান্তের পদ্ধতিগুলি পেতে সক্ষম করবে।
ড্রাগন আইফটস

67

BindingFlags.NonPublicনিজে থেকে কোনও ফলাফল ফেরত দেবে না। এটি সক্রিয় হিসাবে, এর সাথে একত্রিত BindingFlags.Instanceকরে কৌশলটি করে।

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, 
    BindingFlags.NonPublic | BindingFlags.Instance);

একই যুক্তি internalফাংশনগুলিতেও প্রযোজ্য
সুপারটোপি

আমি একই সমস্যা আছে। যদি "এটি" একটি শিশু শ্রেণি হয় এবং আপনি পিতামাতার ব্যক্তিগত পদ্ধতিতে আবেদন করার চেষ্টা করেন তবে কী হবে?
পার্সিয়ান লাইফ

বেস.ব্যাস ক্লাস সুরক্ষিত পদ্ধতিগুলি চাওয়ার জন্য এটি ব্যবহার করা কি সম্ভব?
শিব

51

এবং আপনি যদি নিজেকে সত্যিই সমস্যায় ফেলতে চান তবে একটি এক্সটেনশন পদ্ধতি লিখে এটি কার্যকর করা সহজ করুন:

static class AccessExtensions
{
    public static object call(this object o, string methodName, params object[] args)
    {
        var mi = o.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
        if (mi != null) {
            return mi.Invoke (o, args);
        }
        return null;
    }
}

এবং ব্যবহার:

    class Counter
    {
        public int count { get; private set; }
        void incr(int value) { count += value; }
    }

    [Test]
    public void making_questionable_life_choices()
    {
        Counter c = new Counter ();
        c.call ("incr", 2);             // "incr" is private !
        c.call ("incr", 3);
        Assert.AreEqual (5, c.count);
    }

14
বিপজ্জনক? হ্যাঁ. আমার ইউনিট টেস্টিং নেমস্পেসে মোড়ানো অবস্থায় একটি দুর্দান্ত সহায়ক এক্সটেনশন। এর জন্য ধন্যবাদ.
রবার্ট ওয়াহেলার

5
যদি আপনি এই পদ্ধতিটি থেকে ডাকা প্রকৃত ব্যতিক্রম সম্পর্কে যত্নশীল হন তবে টার্গেটইনভোকেশনএক্সেপশন ধরা পড়লে পরিবর্তে ক্যাচ ব্লকে চেষ্টা করে এর অভ্যন্তরীণ ব্যতিক্রম পুনরায় নিক্ষেপ করা ভাল ধারণা। আমি আমার ইউনিট পরীক্ষার সাহায্যকারী এক্সটেনশনে এটি করি।
স্লোভোডান সাভকোভিক

2
প্রতিবিম্ব বিপজ্জনক? হুমম ... সি #, জাভা, পাইথন ... আসলে সমস্ত কিছু বিপজ্জনক এমনকি বিশ্বও: ডি আপনি কীভাবে এটি নিরাপদে করবেন সে সম্পর্কে আপনাকে যত্ন নিতে হবে ...
কিংবদন্তি

16

মাইক্রোসফ্ট সম্প্রতি এই উত্তরগুলির বেশিরভাগ রেকর্ডিং প্রতিবিম্ব এপিআই সংশোধন করেছে । নিম্নলিখিতগুলিতে আধুনিক প্ল্যাটফর্মগুলিতে কাজ করা উচিত (জ্যামারিন.ফর্ম এবং ইউডাব্লুপি সহ):

obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);

বা এক্সটেনশন পদ্ধতি হিসাবে:

public static object InvokeMethod<T>(this T obj, string methodName, params object[] args)
{
    var type = typeof(T);
    var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
    return method.Invoke(obj, args);
}

বিঃদ্রঃ:

  • যদি পছন্দসই পদ্ধতিটি জেনেরিকের একটি সুপারক্লাসে থাকে objতবে Tঅবশ্যই স্পষ্টভাবে সুপারক্লাসের ধরণে সেট করা উচিত।

  • পদ্ধতিটি যদি অ্যাসিক্রোনাস হয় তবে আপনি ব্যবহার করতে পারেন await (Task) obj.InvokeMethod(…)


এটি ইউডাব্লুপি। নেট সংস্করণে কমপক্ষে কাজ করে না কারণ এটি কেবল সর্বজনীন পদ্ধতির জন্যই কাজ করে: "নির্দিষ্ট সংখ্যার সাথে মিল রেখে বর্তমান টাইপে ঘোষণা করা সমস্ত পাবলিক পদ্ধতি রয়েছে এমন একটি সংগ্রহ ফিরিয়ে দেয় "।
Dmytro Bondarenko

1
@ ডমিটারবোনডেরেনকো আমি এটি ব্যক্তিগত পদ্ধতির বিপরীতে পরীক্ষা করেছি এবং এটি কার্যকর হয়েছে। আমি অবশ্য তা দেখেছি। ডকুমেন্টেশন থেকে এটি কেন আলাদা আচরণ করে তা নিশ্চিত নয়, তবে কমপক্ষে এটি কাজ করে।
ওভেন জেমস

হ্যাঁ, আমি অন্য সমস্ত উত্তর অপ্রচলিত কল করব না, যদি ডকুমেন্টেশনটি GetDeclareMethod()কেবল একটি পাবলিক পদ্ধতি পুনরুদ্ধার করতে ব্যবহার করার উদ্দেশ্যে তৈরি করা হয়।
ভর ডট নেট

10

উত্তরাধিকারের মাধ্যমে এটি করা সম্ভব না আপনি কি নিশ্চিত? সমস্যার সমাধান করার সময় আপনার প্রতিফলনটি সবচেয়ে শেষের দিকে লক্ষ্য করা উচিত, এটি রিফ্যাক্টরিং করে, আপনার কোড বোঝে এবং কোনও স্বয়ংক্রিয় বিশ্লেষণকে আরও কঠিন করে তোলে।

দেখে মনে হচ্ছে আপনার ঠিক একটি ড্রইআইটেম 1, ড্রই আইটেম 2 ইত্যাদি ক্লাস থাকা উচিত যা আপনার ডায়নমেথোদকে ওভাররাইড করে।


1
@ বিল কে: অন্যান্য পরিস্থিতি বিবেচনা করে আমরা এর জন্য উত্তরাধিকার ব্যবহার না করার সিদ্ধান্ত নিয়েছি, তাই প্রতিচ্ছবি ব্যবহার করব। বেশিরভাগ ক্ষেত্রে, আমরা এটি সেভাবে করব।
জেরোমি ইরভিন সাউথ

8

বিশেষত ব্যক্তিগত সদস্যদের প্রতিফলন ভুল

  • প্রতিবিম্ব বিরতি ধরনের সুরক্ষা। আপনি এমন একটি পদ্ধতিতে চেষ্টা করতে পারেন যা বিদ্যমান নেই (অন্যটি), বা ভুল পরামিতিগুলি সহ, বা খুব বেশি পরামিতি সহ, বা যথেষ্ট নয় ... বা এমনকি ভুল ক্রমেও (এটি আমার প্রিয় :))। উপায় দ্বারা রিটার্নের ধরণটিও পরিবর্তিত হতে পারে।
  • প্রতিবিম্ব ধীর।

ব্যক্তিগত সদস্যদের প্রতিচ্ছবি এনক্যাপসুলেশন নীতিটি ভেঙে দেয় এবং এইভাবে আপনার কোডটি নিম্নলিখিতটিতে প্রকাশ করে:

  • আপনার কোডের জটিলতা বাড়ান কারণ এটি ক্লাসগুলির অভ্যন্তরীণ আচরণ পরিচালনা করতে হয়। যা গোপন তা লুকিয়ে রাখা উচিত।
  • আপনার কোডটিকে ভাঙ্গা সহজ করে তোলে কারণ এটি সংকলিত হবে তবে পদ্ধতিটি এর নাম পরিবর্তন করলে চলবে না।
  • প্রাইভেট কোডটিকে ভাঙ্গা সহজ করে তোলে কারণ এটি ব্যক্তিগত থাকলে এটি সেভাবে কল করার উদ্দেশ্যে নয়। সম্ভবত ব্যক্তিগত পদ্ধতি কল করার আগে কিছু অভ্যন্তরীণ অবস্থা আশা করে।

আমি যদি যাইহোক এটি করা আবশ্যক?

এমন কেসগুলি রয়েছে, যখন আপনি কোনও তৃতীয় পক্ষের উপর নির্ভর করেন বা আপনার কিছু এপিআই উন্মুক্ত না করা দরকার হয়, আপনাকে কিছু প্রতিবিম্ব করতে হবে। কেউ কেউ নিজের মালিকানাধীন কিছু ক্লাস পরীক্ষা করার জন্য এটি ব্যবহার করে তবে তারা কেবল পরীক্ষার জন্য অভ্যন্তরীণ সদস্যদের অ্যাক্সেস দেওয়ার জন্য ইন্টারফেসটি পরিবর্তন করতে চান না।

আপনি যদি এটি করেন তবে এটি সঠিকভাবে করুন

  • সহজে ভাঙ্গা প্রশমন করুন:

ইস্যুতে ভাঙ্গা সহজ সমাধানের জন্য, ইউনিট পরীক্ষায় যা কোনও ধারাবাহিক ইন্টিগ্রেশন বিল্ড বা এ জাতীয় চলতে পারে সেগুলি পরীক্ষা করে কোনও সম্ভাব্য বিরতি সনাক্ত করা ভাল। অবশ্যই, এর অর্থ হল আপনি সর্বদা একই সমাবেশটি ব্যবহার করেন (এতে ব্যক্তিগত সদস্য রয়েছে)। আপনি যদি একটি গতিশীল লোড এবং প্রতিবিম্ব ব্যবহার করেন তবে আপনি আগুনের সাথে খেলতে পছন্দ করেন তবে কলটি যে ব্যতিক্রম করতে পারে তা আপনি সর্বদা ধরতে পারেন।

  • প্রতিবিম্বের অলসতা প্রশমিত করুন:

নেট ফ্রেমওয়ার্কের সাম্প্রতিক সংস্করণগুলিতে, ক্রিয়েটডেলিগেট 50 ফ্যাক্টরটি দ্বারা মেথডইনফো ডাকবে:

// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType, 
  BindingFlags.NonPublic | BindingFlags.Instance);

// Here we create a Func that targets the instance of type which has the 
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
                 typeof(Func<TInput, TOutput[]>), this);

drawকল প্রায় 50x তুলনায় দ্রুততর হবে MethodInfo.Invoke ব্যবহার drawএকটি আদর্শ হিসাবে Funcযে মত:

var res = draw(methodParams);

বিভিন্ন পদ্ধতির অনুরোধে বেঞ্চমার্ক দেখতে আমার এই পোস্টটি দেখুন


1
যদিও আমি পেয়েছি নির্ভরতা ইনজেকশনটি ইউনিট-পরীক্ষার একটি পছন্দনীয় উপায় হওয়া উচিত, আমার ধারণা আমি সতর্কতার সাথে ব্যবহার করা ইউনিটগুলিতে অ্যাক্সেসের প্রতিচ্ছবি ব্যবহার করা সম্পূর্ণ খারাপ নয় যা অন্যথায় পরীক্ষার জন্য অ্যাক্সেসযোগ্য হবে। ব্যক্তিগতভাবে আমি মনে করি পাশাপাশি সাধারণ [জনসাধারণ] [সুরক্ষিত] [প্রাইভেট] সংশোধক আমাদেরও হওয়া উচিত [পরীক্ষা] [রচনা] সংশোধনকারী যাতে প্রতিটি কিছুকে সর্বজনীন করার জন্য বাধ্য না করে এই পর্যায়ে নির্দিষ্ট কিছু জিনিস দৃশ্যমান হওয়া সম্ভব হয় ( এবং সুতরাং সেই পদ্ধতিগুলি পুরোপুরি নথিভুক্ত করতে হবে)
অ্যান্ড্রু প্যাট

1
বেসরকারী সদস্যদের প্রতিবিম্বিত করার সমস্যাগুলির তালিকা তৈরির জন্য ধন্যবাদ ফ্যাব, এটির ব্যবহার সম্পর্কে আমার কেমন অনুভূতি হয়েছে তা পর্যালোচনা করার কারণ হয়েছে এবং সিদ্ধান্তে পৌঁছেছে ... আপনার ব্যক্তিগত সদস্যদের ইউনিট-টেস্টের প্রতিচ্ছবি ব্যবহার করা ভুল, তবে কোড-পাথকে অনির্ধারিত রেখে দেওয়া হচ্ছে সত্যিই ভুল।
অ্যান্ড্রু পেট

2
কিন্তু যখন এটি ইউনিট পরীক্ষার ক্ষেত্রে সাধারণত-ইউনিট-টেস্টেবল লিগ্যাসি কোডের পরীক্ষা করার কথা না, এটি করার উজ্জ্বল উপায়
TS

2

আপনি যে ছবি আঁকতে চান তা প্রতিটি ধরণের আলাদা আলাদা আঁকার পদ্ধতি নাও থাকতে পারে? তারপরে ওভারলোড হওয়া অঙ্কন পদ্ধতিটি কল করুন আইটেম টাইপের ধরণের অবজেক্টটিতে আঁকতে passing

আইটেম টাইপ সত্যিকার অর্থে বিভিন্ন ধরণের জিনিসকে বোঝায় কিনা তা আপনার প্রশ্নটি পরিষ্কার করে না।



1

বস্তুর উদাহরণে সুরক্ষা স্তর সত্ত্বেও যে কোনও পদ্ধতিতে অনুরোধ জানানো হয়। উপভোগ করুন!

public static object InvokeMethod(object obj, string methodName, params object[] methodParams)
{
    var methodParamTypes = methodParams?.Select(p => p.GetType()).ToArray() ?? new Type[] { };
    var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
    MethodInfo method = null;
    var type = obj.GetType();
    while (method == null && type != null)
    {
        method = type.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
        type = type.BaseType;
    }

    return method?.Invoke(obj, methodParams);
}

0

এটি কোথায় যাচ্ছে এবং এই থ্রেডের কিছু লোক কেন "এটি এখনও কাজ করছে না" অভিযোগ করার জন্য এই (পরিপূরক) উত্তরটি (এটি কখনও কখনও উত্তর) পড়ুন

আমি এখানে উত্তরগুলির একটি হিসাবে ঠিক একই কোড লিখেছি । তবে আমার তখনও একটি সমস্যা ছিল। আমি ব্রেক পয়েন্ট রেখেছি

var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );

এটি কার্যকর করা হয়েছে কিন্তু mi == null

এবং জড়িত সমস্ত প্রকল্পের "পুনর্নির্মাণ" না করা পর্যন্ত এটি এরূপ আচরণ অব্যাহত রাখে। প্রতিবিম্বের পদ্ধতিটি তৃতীয় সমাবেশে বসে আমি একটি অ্যাসেম্বলির পরীক্ষা করছিলাম। এটি সম্পূর্ণ বিভ্রান্তিকর ছিল তবে আমি পদ্ধতিগুলি আবিষ্কার করতে তাত্ক্ষণিক উইন্ডো ব্যবহার করেছি এবং আমি দেখতে পেলাম যে একটি ব্যক্তিগত পদ্ধতিতে আমি পরীক্ষার একক চেষ্টা করেছি তার পুরানো নাম ছিল (আমি এর নাম দিয়েছি)। এটি আমাকে বলেছিল যে ইউনিট পরীক্ষা প্রকল্পটি তৈরি করে - এমনকি কোনও কারণ প্রকল্পের জন্য এটি পরীক্ষা না করে পুরানো সমাবেশ বা পিডিবি এখনও বাইরে আছে। "পুনর্নির্মাণ" কাজ করেছে


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.