2016-11-28 5 views
5

मैं निम्नलिखित वर्ग पदानुक्रम:मैं संकलित अभिव्यक्तियों के लिए सी # विधियों को कैसे परिवर्तित कर सकता हूं?

public class Parent 
{ 
    [DebuggerStepThrough] 
    public void SayParent() 
    { 
     Console.WriteLine("Parent"); 
    } 
} 

public sealed class Child : Parent 
{ 
    private static int _number = 0; 
    public Child() // May contain parameter i.e. not always parameterless consctructor 
    { 
     _number++; 
    } 

    [DebuggerStepThrough] 
    public void SayInstance() 
    { 
     Console.WriteLine("{0}-Say", _number); 
    } 

    [DebuggerStepThrough] 
    public void SayInstanceWithArg(string input) 
    { 
     Console.WriteLine("{0}-Say: {1}", _number, input); 
    } 

    [DebuggerStepThrough] 
    public static void SayStatic() 
    { 
     Console.WriteLine("{0}-Say", _number); 
    } 

    [DebuggerStepThrough] 
    public static void SayStaticWithArg(string input) 
    { 
     Console.WriteLine("{0}-Say: {1}", _number, input); 
    } 

    [DebuggerStepThrough] 
    public static Task SayStaticWithArgAndReturn(string input) 
    { 
     Console.WriteLine("{0}-Say: {1}", _number, input); 
     return null; 
    } 
} 

मैं तथापि प्रतिबिंब का उपयोग कर प्रदर्शन मैं Delegate का सहारा की जरूरत है सुधार करने के लिए किसी भी समय पर Child का एक नया उदाहरण के लिए इनमें से किसी भी आह्वान करने के लिए सक्षम होना चाहिए और/या Compiled Expressions

इसलिए उदाहरण के लिए मैं हो सकता है:

var instanceOne = new Child(); 
var instanceTwo = new Child(); 

जिसके लिए मैं क्रम में करने की आवश्यकता होगी इन तरीकों उन इसकी जरूरत है कि के लिए तर्क गुजर आह्वान। ध्यान दें कि उनमें कुछ पैरामीटर स्वीकार करने वाले static और instance विधियां शामिल हैं।

मैं अब तक "SayInstance" विधि के लिए निम्नलिखित की कोशिश की है:

var sayInstanceMethod = typeof(Child) 
     .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) 
     .Where(m => m.GetCustomAttributes(typeof(DebuggerStepThroughAttribute), true).Length > 0) 
     .Where(t => t.Name == "SayInstance") 
     .First() 

और फिर:

var instance = Expression.Constant(new Child()); // This should NOT be Constant, but then what should it be?! 
var mCallInstance = Expression.Call(instance, sayInstanceMethod); 

Action action = Expression.Lambda<Action>(mCallInstance).Compile(); 

action(); 
action(); // I need to pass in a new instance of Child to this method somehow 

हालांकि मैं हो रही है:

1-Say 
1-Say 

के बजाय:

1-Say 
2-Say 

मुझे संदेह है कि यह Expression.Constant के कारण है, लेकिन मुझे यह पता नहीं लगा सकता कि मैं इसे Child के रनटाइम पर अपने लक्ष्य के रूप में कैसे स्वीकार कर सकता हूं।

मैं निराश हूँ जब यह :-(

मैं मूल रूप से लागू करने के लिए क्या जॉन स्कीट का उल्लेख है HERE या तो Delegates या Compiled Expressions का उपयोग कर कोशिश कर रहा हूँ Expressions लिए आता है।

किसी भी मदद की बहुत सराहना की है।

+2

आप कन्स्ट्रक्टर पर संख्या बढ़ा रहे हैं। और यह स्थैतिक क्षेत्र है। तो, आपके पास कभी भी नतीजा नहीं होगा। _number फ़ील्ड को एक निजी क्षेत्र में स्टोर करें –

+1

यह सुनिश्चित करने का तरीका है कि अंतिम परिणाम काम करेगा। मुख्य समस्या यह है कि मैं एक अभिव्यक्ति बनाने में असमर्थ हूं जो रनटाइम पर 'चाइल्ड' के नए उदाहरण को स्वीकार करता है। – MaYaN

+1

लाइनें 'var instanceOne = new child(); 'और' var instanceTwo = new child();' उसी परीक्षण में भाग गया जो 'क्रिया();' दो बार 'कहता है? – Mat

उत्तर

3

अगर मैं सही ढंग से समझ में आ, तो आप इस तरह, पैरामीटर का उपयोग करना:

var instanceOne = new Child(); 
var instanceTwo = new Child();    
var instance = Expression.Parameter(typeof(Child), "c"); // This should NOT be Constant, but then what should it be?! 
var mCallInstance = Expression.Call(instance, sayInstanceMethod); 
Action<Child> action = Expression.Lambda<Action<Child>>(mCallInstance, instance).Compile(); 

action(instanceOne); 
action(instanceTwo); // I need to pass in a new instance of Child to this method somehow 
बेशक

इस उत्पादन 1, 2 नहीं करेगा क्योंकि आपका संख्याएँ क्षेत्र स्थिर है और दो में से निर्माण के बाद दोनों के लिए मान 2 है।

संपादित करें। यदि आपको तर्क के साथ विधि कॉल करने की आवश्यकता है - अधिक पैरामीटर घोषित करें। उदाहरण के लिए यदि SayInstance में टाइप स्ट्रिंग का एक तर्क है, तो:

var instanceOne = new Child(); 
var instanceTwo = new Child();    
var instance = Expression.Parameter(typeof(Child), "instance"); 
var arg = Expression.Parameter(typeof(string), "arg"); 
var mCallInstance = Expression.Call(instance, sayInstanceMethod, arg); 
Action<Child,string> action = Expression.Lambda<Action<Child,string>>(mCallInstance, instance, arg).Compile(); 

action(instanceOne, "one"); 
action(instanceTwo, "two"); 
+0

तुम मेरे दोस्त, मेरा दिन बना दिया! यह ठीक वैसा ही है जैसा मुझे चाहिए। धन्यवाद :-) – MaYaN

+0

बस मुझे लालची हो रही है! यदि मैं चाहता हूं तो मैं तर्क में भी गुजरने के लिए इसका विस्तार कैसे कर सकता हूं? उदाहरण: 'सार्वजनिक शून्य SayInstanceWithArg (स्ट्रिंग इनपुट)' – MaYaN

+0

"कार्रवाई" या निरंतर के रूप में तर्क के रूप में पास? – Evk

2

इसे आज़माएं, मेरे लिए यह पैरामीटर पैरामीटर रहित कन्स्ट्रक्टर के लिए है, लेकिन यह है कि आपको इसकी आवश्यकता है:

var instance = Expression.New(typeof(Child).GetConstructor(new Type[0])); 
var mCallInstance = Expression.Call(instance, sayInstanceMethod); 

Action action = Expression.Lambda<Action>(mCallInstance).Compile(); 

action(); 
action(); // I need to pass in a new instance of Child to this method someh 
+1

कमाल! लगभग वहां हालांकि (मेरे उदाहरण के बावजूद) मुझे इसे पैरामीटरयुक्त कन्स्ट्रक्टर के साथ काम करने की ज़रूरत है, मेरे पास पहले से ही ऑब्जेक्ट का एक नया उदाहरण बनाने की प्रक्रिया है, क्या कोई ऐसा तरीका है जहां मैं उस ऑब्जेक्ट में पास कर सकता हूं जिसे मैंने पहले ही बनाया है? – MaYaN

संबंधित मुद्दे