Hi Profis,
ich habe eine - für mich zumindest - etwas schwierige Frage, die ich mir ohne weiteres nicht beantworten kann. Ich habe eine Liste, welche Elemente vom Typ "object" enthält, also List<object> elements;
Ich möchte nun alle Elemente dieser Liste durchgehen und alle Properties der Elemente in der Liste analysieren, wobei ich NICHT weiß, welcher Typ sich in der Liste befindet. Ich möchte auch keinen Cast durchführen mit einer Case-Anweisung o. Ä. aus dem Grund, dass ich dann die Klassen dadrin beschreiben muss. Es können ca. 200 verschiedene Typen sein (aus dem COM von einem anderen Programm), die jeweils auch mal eine Property, die mich interessiert, aber auch mal 20 Properties haben können, die ich durchsuchen muss.
Das logische Konstrukt, was ich mir vorstelle, damit das vielleicht etwas einfacher zu verstehen ist sieht so aus:
class X
{
List<object> Elements { get; private set; }
public X()
{
this.Elements = new List<object>();
}
public void Scan()
{
// Liste befüllen, dabei sollen die Objekte nicht genau definiert werden.
this.Elements.Add(new FileInfo("test.txt"));
this.Elements.Add(new MyObj("test.txt"));
}
public List<object> GetObjectsFromAllElementsWithMatchFilter(string filter)
{
foreach (var e in this.Elements)
{
// Hier möchte ich zb. nach "test.txt" suchen und zwar in ALLEN Properties von allen unbekannten Objekten in der Liste "Elements".
// Reflection?
foreach (var prop in AllenPropertiesVonDiesemUnbekanntenObject)
{
if (prop.XXX == filter)
yield return e;
}
}
}
}
internal class MyObj
{
public string MyProp { get; set; }
public MyObj(string n)
{
this.MyProp = n;
}
}
Kann mir da jmd helfen?
Vielen Dank 🙂
Sowas kann man leicht mittels [Artikel] Reflection und Metaprogrammierung lösen.
Aber wo du "COM" erwähnst: Ich hab bisher selten damit gearbeitet, aber wenn, dann hat Reflection selten so funktioniert, wie man das von "normalen" CLR-Typen gewohnt ist.
Ja, das sieht nach einer Lösung für mich aus. 8)
Nur noch einbauen 8o
Hallo nochmal,
ich lese nun mit folgendem Konstrukt:
foreach (MemberInfo memberInfo in typeof(Sketch).GetMembers())
{
if (memberInfo is ConstructorInfo)
{
// Informationen zum Konstruktor
ConstructorInfo constructorInfo = (ConstructorInfo)memberInfo;
Console.WriteLine("Konstruktor:");
Console.WriteLine(constructorInfo.Name);
Console.WriteLine(constructorInfo.Attributes);
foreach (ParameterInfo parameterInfo in constructorInfo.GetParameters())
Console.WriteLine(parameterInfo.Name + " (" + parameterInfo.ParameterType.FullName + ")");
}
if (memberInfo is FieldInfo)
{
// Informationen zum Feld
FieldInfo fieldInfo = (FieldInfo)memberInfo;
Console.WriteLine("Feld:");
Console.WriteLine(fieldInfo.Name + " (" + fieldInfo.FieldType.FullName + ")");
Console.WriteLine(fieldInfo.Attributes);
}
if (memberInfo is MethodInfo)
{
// Informationen zur Methode
MethodInfo methodInfo = (MethodInfo)memberInfo;
Console.WriteLine("Methode:");
Console.WriteLine(methodInfo.Name + " (" + methodInfo.ReturnType.FullName + ")");
Console.WriteLine(methodInfo.Attributes);
foreach (ParameterInfo parameterInfo in methodInfo.GetParameters())
Console.WriteLine(parameterInfo.Name + " (" + parameterInfo.ParameterType.FullName + ")");
}
if (memberInfo is PropertyInfo)
{
// Informationen zum Property
PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
Console.WriteLine("Eigenschaft:");
Console.WriteLine(propertyInfo.Name + " (" + propertyInfo.PropertyType.FullName + ")");
Console.WriteLine(propertyInfo.Attributes);
// ein Property muss nicht zwingend Getter UND Setter haben!
if (propertyInfo.CanRead)
Console.WriteLine(propertyInfo.GetGetMethod(true).Name);
if (propertyInfo.CanWrite)
Console.WriteLine(propertyInfo.GetSetMethod(true).Name);
}
Console.WriteLine();
}
den Typ Sketch aus. Herauskommt folgende Ausgabe:
Methode:
Destructor (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
GetMetaObject (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
IsA (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
IsAKindOf (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
GetImpl (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
SetImpl (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
IsNull (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
IsEqual (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
SurChargeQI (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
ChangeComponentState (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
get_Application (INFITF.Application)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
get_Parent (INFITF.CATBaseDispatch)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
get_Name (System.String)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
set_Name (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
oNameBSTR (System.String&)
Methode:
GetItem (INFITF.CATBaseDispatch)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
IDName (System.String&)
Methode:
get_GeometricElements (MECMOD.GeometricElements)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
get_Constraints (MECMOD.Constraints)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
get_Factory2D (MECMOD.Factory2D)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
get_CenterLine (MECMOD.Line2D)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
set_CenterLine (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
oLine (MECMOD.Line2D)
Methode:
get_AbsoluteAxis (MECMOD.Axis2D)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract, SpecialName
Methode:
GetAbsoluteAxisData (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
oAxisData (System.Array)
Methode:
SetAbsoluteAxisData (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
iAxisData (System.Array)
Methode:
OpenEdition (MECMOD.Factory2D)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
InverseOrientation (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Methode:
Evaluate (System.Void)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, Abstract
Eigenschaft:
Application (INFITF.Application)
None
get_Application
Eigenschaft:
Parent (INFITF.CATBaseDispatch)
None
get_Parent
Eigenschaft:
Name (System.String)
None
get_Name
set_Name
Eigenschaft:
GeometricElements (MECMOD.GeometricElements)
None
get_GeometricElements
Eigenschaft:
Constraints (MECMOD.Constraints)
None
get_Constraints
Eigenschaft:
Factory2D (MECMOD.Factory2D)
None
get_Factory2D
Eigenschaft:
CenterLine (MECMOD.Line2D)
None
get_CenterLine
set_CenterLine
Eigenschaft:
AbsoluteAxis (MECMOD.Axis2D)
None
get_AbsoluteAxis
Jetzt habe ich allerdings oben den Typ "Sketch" explizit definiert (das möchte ich ja nicht, da es dynamisch sein soll). Ich habe nun ja meine Liste bzw. mein Dictionary mit den Objekten vom Typ Sketch (unter Anderem) und wenn ich nun die Methode GetType() auf ein Objekt vom Typ Sketch ausführe - der Schleifenbeginn sieht folgendermaßen geändert aus:
foreach (MemberInfo memberInfo in this.AllElements.First().Value.GetType().GetMembers())
, um genau obige Ausgabe zu erhalten, damit ich auf die Methoden per Reflection zugreifen kann, bekomme ich jedoch nur folgende Ausgabe:
Methode:
GetLifetimeService (System.Object)
PrivateScope, Public, Final, Virtual, HideBySig, VtableLayoutMask, HasSecurity
Methode:
InitializeLifetimeService (System.Object)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, HasSecurity
Methode:
CreateObjRef (System.Runtime.Remoting.ObjRef)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask, HasSecurity
requestedType (System.Type)
Methode:
ToString (System.String)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Methode:
Equals (System.Boolean)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
obj (System.Object)
Methode:
GetHashCode (System.Int32)
PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask
Methode:
GetType (System.Type)
PrivateScope, Public, HideBySig
Es fehlen also die wichtigen Member. Vor allendingen sind das die, die mich interessieren und welche auch public sind. Wenn ich mir die Definition von Sketch anschaue (es ist ein COM-Typ), dann sieht das folgendermaßen aus:
namespace MECMOD
{
[TypeLibType(4160)]
[Guid("EE3021B2-3B09-11D1-A26C-0000F87546FD")]
public interface Sketch : AnyObject
{
[DispId(1610940421)]
Axis2D AbsoluteAxis { get; }
[DispId(1610874880)]
Application Application { get; }
[DispId(1610940419)]
Line2D CenterLine { get; set; }
[DispId(1610940417)]
Constraints Constraints { get; }
[DispId(1610940418)]
Factory2D Factory2D { get; }
[DispId(1610940416)]
GeometricElements GeometricElements { get; }
[DispId(1610874881)]
CATBaseDispatch Parent { get; }
[TypeLibFunc(65)]
[DispId(1610743817)]
void ChangeComponentState();
[DispId(1610940425)]
void CloseEdition();
[DispId(1610743808)]
[TypeLibFunc(65)]
void Destructor();
[DispId(1610940427)]
void Evaluate();
[DispId(1610874882)]
string get_Name();
[DispId(1610940422)]
void GetAbsoluteAxisData(Array oAxisData);
[TypeLibFunc(65)]
[DispId(1610743812)]
void GetImpl();
[DispId(1610874884)]
CATBaseDispatch GetItem(ref string IDName);
[DispId(1610743809)]
[TypeLibFunc(65)]
void GetMetaObject();
[DispId(1610940426)]
void InverseOrientation();
[TypeLibFunc(65)]
[DispId(1610743810)]
void IsA();
[TypeLibFunc(65)]
[DispId(1610743811)]
void IsAKindOf();
[TypeLibFunc(65)]
[DispId(1610743815)]
void IsEqual();
[TypeLibFunc(65)]
[DispId(1610743814)]
void IsNull();
[DispId(1610940424)]
Factory2D OpenEdition();
[DispId(1610874882)]
void set_Name(ref string oNameBSTR);
[DispId(1610940423)]
void SetAbsoluteAxisData(Array iAxisData);
[TypeLibFunc(65)]
[DispId(1610743813)]
void SetImpl();
[TypeLibFunc(65)]
[DispId(1610743816)]
void SurChargeQI();
}
}
Es ist also ein Interface. Nun habe ich jedoch auch schon viele andere Konstrukte probiert, u. A. mit der Library "Fasterflect" und auch damit komme ich, egal welche Parameter ich übergebe, nicht an diese Member.
Bin langsam ratlos X(
Hallo,
das ist im Prinzip das was dN!3L schon angekündigt hat in Bezug auf COM und Reflection.
Schau dir mal in COM-Wrapper an wie COM Objekte aus .Net angesprochen werden. Du bekommst nicht das eigentliche COM Objekt, sondern einen Wrapper der die Aufrufe weiterleitet und genau auf den Wrapper wendest du Reflection an. Und der hat die von dir gefundenen Methoden.
Ja, habe mir schon gedacht, dass es sich um dieses schon angekündigte Problem handelt. Aber ich steige da bezüglich Komplexität aus. X(
Habe ich eine Chance von dem Objekt an die Member zu kommen oder ist das unmöglich? Das Problem ist ja eigentlich nur, dass ich den Typ nicht vorher festlegen will, das ist alles. 🤔
Echt blöd...