2016-10-25 13 views
8

Mam kilka przypadków, w których muszę wywoływać nazwy metod od nazw klas.Dynamicznie wywołująca metoda i nazwa klasy

string scenario1 = "MockScenario1"; 
string scenario2 = "MockScenario2"; 

MockScenario1.GetInfo(); 
MockScenario2.GetInfo(); 

Jak mogę dynamicznie używać strun zadzwonić nazwę metody tutaj jak

scenario1.GetInfo() 
scenario2.GetInfo() 

Starałem się znaleźć wszystkie opcje przez smyczkową i kontroli przestrzeni znaleźć opcje związane. Jakieś sugestie?

ja próbowałem poniżej i staramy się nazwa klasy generowane dynamicznie

Poniższy kod generowany nazwa metody dynamicznie

string methodName = "hello"; 

//Get the method information using the method info class 
MethodInfo mi = this.GetType().GetMethod(methodName); 

//Invoke the method 
// (null- no parameter for the method call 
// or you can pass the array of parameters...) 
mi.Invoke(this, null); 

bardziej jasne scenariusz: Próbuję wysłać nazwę klasy jako parametr MockScenario1 i MockScenario2 to nazwy klas.

string scenarioCats = "MockScenario1"; 
string scenarioDogs = "MockScenario2"; 
GetResult(scenarioCats); 
GetResult(scenarioDogs); 

public static void GetCatsResult(string scenarioCats){ 
scenarioCats obj = new scenarioCats(); 
    obj.GetInfo();  
} 
public static void GetDogsResult(string scenarioDogs){ 
scenarioDogs obj = new scenarioDogs(); 
    obj.GetInfo();  
} 
+1

Możliwy duplikat [string na nazwę zmiennej] (http://stackoverflow.com/questions/1293549/string-to-variable-name) – Residuum

+1

Sprawdź poniższy link http://stackoverflow.com/questions/1 044455/c-sharp-reflection-how-to-get-class-reference-from-string –

+0

Zobacz na http://stackoverflow.com/a/39793450/5962841 pokazuje przykład uzyskania metody z klasy – Mafii

Odpowiedz

15

Jak utworzyć wystąpienie typu z jej ciąg znaków:

string scenario1 = "TheNamespace.MockScenario1"; 
Type theType = this.GetType().Assembly.GetType(scenario1); 
var theInstance = (MockScenario1)Activator.CreateInstance(theType); 
theInstance.GetInfo(); 

Będzie lepiej, jeśli zajęcia wdrożyć wspólny interfejs, na przykład IGetInfoAware, a następnie można napisać bardziej rodzajowe ładowarka:

var theInstance = (IGetInfoAware)Activator.CreateInstance(theType); 

Uwaga: trzeba dostarczyć pełną nazwę klasy dla scenario1 i scenario2

Zobacz Activator.CreateInstance

EDIT:

Jak @Georg wskazał, jeśli typ nie jest zadeklarowana w zespole obiektów kontekstowych, to jest konieczne pierwszy zespół, aby uzyskać gdzie typ jest gospodarzem:

var theAssembly = (
    from Assembly assembly in AppDomain.CurrentDomain.GetAssemblies() 
    where (assembly.FullName == "TheNamespace.AssemblyName") 
    select assembly 
) 
.FirstOrDefault(); 

if (theAssembly!= null){ 
    Type theType = theAssembly.GetType(scenario1); 
    var theInstance = (IGetInfoAware)Activator.CreateInstance(theType); 
    theInstance.GetInfo(); 
} 

Jeśli z jakiegoś powodu nie jest znana nazwa zespołu do ciebie, to typ może być rozwiązany jak następuje:

public Type GetTypeFromString(String typeName) 
{ 
    foreach (Assembly theAssembly in AppDomain.CurrentDomain.GetAssemblies()) 
    { 
     Type theType = theAssembly.GetType(typeName); 
     if (theType != null) 
     { 
      return theType;      
     } 
    } 
    return null; 
} 
+1

Myślę, że założenie, że typ znajduje się w zestawie typów obiektów kontekstowych, jest wadą projektową. Jeśli ktoś odziedziczy klasę w innym zestawie, to już zmienia to zachowanie, nawet jeśli nic innego się nie zmieni. Powinieneś lepiej pozwolić klientowi wybrać zestaw, w którym chcesz przeszukać typ lub możesz oczekiwać nazwy typu kwalifikowanego do montażu. – Georg

+0

@ Georg, to dobra uwaga, zaktualizowałem odpowiedź, aby poradzić sobie ze scenariuszem, który wskazałeś. –

4

Można użyć refleksji:

Type thisType = this.GetType(); 
MethodInfo theMethod =  thisType.GetMethod(FunctionName); 
theMethod.Invoke(this, userParameters); 
+0

Jest to nazwa typu podana jako ciąg znaków, a nie nazwa funkcji. –

+0

Powinieneś wpisać nazwę typu, jeśli nie powtarzasz metody na aktualnej klasie – Hadi

+0

moim zamiarem jest przekazanie mockscenario1,2,3 itd. Jako parametrów. Z powyższym kodem muszę nadać implikację classname i jest ona ściśle związana. – Kurkula

3

Można użyć wzorca projektowania poleceń. Więc użyjesz tablicy haszującej do zapisania łańcucha jako klucza w mapie mieszania, a wtedy twoja funkcja będzie wartością mieszającej mapy. Następnie, gdy chcesz wywołać swoją funkcję, wymówisz hashmap.get ("yourString"). To zwróci funkcję zapisaną jako wartość i możesz ją wywołać stamtąd.

+0

Witaj w [so], wskazówka: dodawanie kodu jest zawsze dobrym pomysłem ... zobacz wszystkie inne odpowiedzi. –

3

Proponuję użyć Dictionary<String, Action>, gdzie można odłożyć wszystkie scenariusze i ich nazwy, np.

private static Dictionary<String, Action> s_Scenario = 
    new Dictionary<String, Action>() { 
    {"MockScenario1",() => MockScenario1.GetInfo()}, 
    {"MockScenario2",() => MockScenario2.GetInfo()}, 
    }; 

... 

s_Scenario["MockScenario1"](); 
s_Scenario["MockScenario2"](); 
+1

Możesz również dodać za pomocą '{" MockScenario1 ", MockScenario1.GetInfo},' bezpośrednio. Uwaga: nie ma nawiasów po 'GetInfo'! –

+0

@Olivier Jacot-Descombes: masz całkowitą rację 'MockScenario1.GetInfo' jest rozwiązaniem rozszerzającym; Po prostu próbowałem pokazać, że * dowolna labda * (niekonieczna pojedyncza metoda) może być używana jako poprawny scenariusz, np. '{" MockScenarios1 and2 ",() => {MockScenario1.GetInfo(); MockScenario2.GetInfo(); }} ' –

+0

moim zamiarem jest przekazanie mockscenario1,2,3 itp. Jako parametrów. – Kurkula

2

Bez podania Namespace do GetType() może zwrócić NULL zawsze (mam do czynienia z tym problemem przed dodaniem tej odpowiedzi.), więc powinno być tak;

Jak wspomniano, chcesz dać ciąg jako parametr

public void GetCatsResult(string scenarioCats) 
     { 
      string item = this.GetType().Namespace + "." + scenarioCats; 
      // combined class string with the namespace 
      Type className = Type.GetType(item); 
      // found the class 
      MethodInfo m = className.GetMethod("GetInfo"); 
      // get the method from class 
      object value = m.Invoke(null,null); 
      // invoke and value will represent the return value. 
     } 

Oto moja klasa Scenariusz,

class Scenario1 
    { 
     public static string GetInfo() 
     { 
      return "GetInfo() called, Scenario1"; 
     } 
    } 

Rezultat; (btw GetCatsResult() zawinął i podany ciąg znaków, który zadeklarowany jako string scenario1 = "Scenario1";)

enter image description here

Nadzieja pomaga,

0

Jeśli jest do testowania można użyć PrivateObject:

using Microsoft.VisualStudio.TestTools.UnitTesting; 

class Class1 
{ 
    public Class1() 
    { 
     MyClass myClass = new MyClass(); 
     PrivateObject myClassPrivateObject = new PrivateObject(myClass, new PrivateType(typeof(MyClass))); 

     myClassPrivateObject.Invoke("MyMethod"); 
    } 
}