I have several external devices which I can communicate to via a common API.
string busIdentifier = "BUS:0:1";
var dev = new CommonDeviceDriver(busIdentifier);
Now I can query the device:
string identifier = dev.QueryIdentifier();
Now I have several concrete driver for example ConcreteDeviceA, ConcreteDeviceB and ConcreteDeviceC. Each of the device driver should have an ìdentifier`.
Now I want to load the right device driver for this previously queried identifer.
How to to that in C#?
Coming from python I would do something like that:
# Have a dictionary where key is identifier and value is the class
supported_devices = {ConcreteDeviceA.identifer : ConcreteDeviceA,
ConcreteDeviceB.identifer : ConcreteDeviceB,
ConcreteDeviceC.identifer : ConcreteDeviceC}
busIdentifier = "BUS:0:1"
dev = CommonDeviceDriver(busIdentifier)
identifier = dev.QueryIdentifier()
concrete_device = supported_devices[identifier](dev) # Get class and call constructor
The simplest way to do this would be a factory method. If you know the available types at compile-time, then you can simply enumerate them in code.
public static DriverBase CreateDriver(string identifier, object device) {
switch (identifier) {
case IDENTIFIER_A: return new ConcreteDeviceA(device);
// etc
}
}
If you don't know all of the types at compile time (or you really object to the above usage), then you can use reflection. Then you can essentially have a dictionary mapping identifier to type (as you have in Python), and instantiate the object either using Activator.CreateInstance, or by looking up its constructor yourself. In that case, you'll have to cast the return object to the base type.
Related
I am trying to add generics to my DAL. There's a list of EF entities and their corresponding repositories. These repositories implement a generic interface. I can't figure out how to instantiantiate the repository.
public T Create(T dtoEntity)
{
string entityClassName = dtoEntity.GetType().Name;
string repositoryClassName = entityClassName + "Repository";
try
{
string entityFullName = entitiesNamespace + entityClassName;
IEntityBase entity = (IEntityBase)assembly.CreateInstance(entityFullName)!;
string repositoryFullName = repositoryNamespace + repositoryClassName;
Type myType = Type.GetType("SmartVisionERP.Dal.SqlServer.Master.DataModel.Config_Accounts,SmartVisionERP.Dal.SqlServer.Master")!;
// IEntityBaseRepository<myType> repository = (IEntityBaseRepository<myType>)assembly.CreateInstance(repositoryFullName)!
IEntityBaseRepository<Config_Accounts> repository = (IEntityBaseRepository<Config_Accounts>)assembly.CreateInstance(repositoryFullName)!;
var list = repository.GetList();
}
catch (Exception)
{
throw;
}
return dtoEntity;
}
I am receiving a dtoEntity, I'm extracting the class name and then build the repository name out of it. For the scenario I am testing, these are "Config_Accounts" and "Config_AccountsRepository".
I am using reflection to instatiate the EF entity, has the same name, it's located in a different assembly. This line works properly, I have the entity.
The repository interface expects a T. IEntityBaseRepository<T> where T : class, IEntityBase, new()
I am getting the correct type in myType variable.
The commented line fails with the message "myType is a variable but is used as a type".
As soon as I write Config_Accounts instead of myType, it works, but this defeats the goal, I am trying to pass the actual type there.
I am out of ideas. Could anyone shed some light? How can I pass to that line a type generated from a string, in such way it actually works?
Thank you
========= EDIT =========
Based on help I received I have changed the code to look like below. I got an error stating "cannot instantiate an interface", which makes sense, so I passed the base class instead. I got the repository in an object, but the object does not expose any of the methods defined in the base class. I am assuming those will need to be exposed and used through more reflection, as suggested in one of the answers.
public T Create(T dtoEntity)
{
string entityClassName = dtoEntity.GetType().Name;
string repositoryClassName = entityClassName + "Repository";
try
{
string entityFullName = $"{entitiesNamespace}{entityClassName}";
IEntityBase entity = (IEntityBase)assembly.CreateInstance(entityFullName)!;
Type template = typeof(EntityBaseRepository<>);
Type myType = Type.GetType("SmartVisionERP.Dal.SqlServer.Master.DataModel.Config_Accounts,SmartVisionERP.Dal.SqlServer.Master")!;
Type genericType = template.MakeGenericType(myType);
object instance = Activator.CreateInstance(genericType);
//string repositoryFullName = repositoryNamespace + repositoryClassName;
//IEntityBaseRepository<Config_Accounts> repository = (IEntityBaseRepository<Config_Accounts>)assembly.CreateInstance(repositoryFullName)!;
//var list = repository.GetList();
}
catch (Exception)
{
throw;
}
return dtoEntity;
}
Generic type arguments need to be known at compile time ( i.e. when jitted). To construct object of a generic type at runtime you need use reflection. I.e. something as this answer ( Thanks to Marco for the link)
Type template = typeof(IEntityBaseRepository<>);
Type genericType = template.MakeGenericType(myType);
object instance = Activator.CreateInstance(genericType);
Ofc, to use the created object you need to use more reflection, since you do not have any compile-time type. You might end up with your compile time type, T, eventually so you can return it, but keep in mind that you will use a fair amount of reflection, and reflection tend to only produce runtime errors, and these errors might not be trivial to decipher.
As an alternative, if the goal is to map some set of types to some other types, one to one, you might consider using some other pattern, for example the visitor-pattern. This will require more code since you need some mapping code for each entity type. But it has the advantage of being type safe. Some types of implementations can force the developer to add any corresponding mappings when a new type is added, and therefore reduce the risk of runtime errors.
Since I do not know your particular circumstance I cannot know what the best solution is. But whenever dealing with reflection it can be a good idea to take a moment to consider if the benefit is worth the loss of type safety.
How can I create a collection of types and instances with Contains/ContainsKey/Any functionality? I've tried using dictionaries, valuetuple lists, and looked into other options, but am consistently stymied by is a type, which is not valid in the given context errors.
For example, here is my List + LINQ attempt with this error:
var activeReports = new List<(Type Type, IReport Instance)>();
if (activeReports.Any(x => x.Type == Reports.Daily))
{
};
and here is my dictionary attempt:
var activeReports = new Dictionary<Type, IReport>();
if (activeReports.ContainsKey(Reports.Daily))
{
};
In both attempts, the is a type, which is not valid in the given context error occurs on Reports.Daily.
Context: I'm trying to create a collection of active reports from a large group of possibilities.
The nomenclature starts to eat its own tail here, which is confusing. What you need to do is make sure you're sending the methods a Type object, as opposed to the actual type. A Type object describes a type—and includes a ton of useful metadata about it.
You can get a Type object by using the built-in typeof() operator on the type (e.g., typeof(Reports.Daily)):
var activeReports = new Dictionary<Type, IReport>();
if (activeReports.ContainsKey(typeof(Reports.Daily))) { … }
Alternatively, if you already have an existing instance of a type, you can get its Type object dynamically at runtime by using the .GetType() method on the existing object instance:
var dailyReport = new Reports.Daily();
var activeReports = new Dictionary<Type, IReport>();
if (activeReports.ContainsKey(dailyReport.GetType())) { … }
Note: GetType() is defined on the base Object class and, thus, available to all objects in C#, regardless of their type.
My Problem
I have a Problem which i can not solve my self. I dont want to use so much code, because i have multiple Classes which extend another class (in my case its called "Data").
I have a log file, where each Data Group is beginning with a specific Group Name, for example "MitarbeiterSet". The abstract Data-Class is used to prefent to much code, where I implemented variables like "String[] data" (for the data beeing parsed from the log file e.g. < 101 4 3 6 3 30 80 2 0 0 1 300 >) or "static String parseInduction", which is used to determin, if this Class is the right one to create Objects from.
I have another Class, called ParseMonitor, which creates the StreamReader to parse the log-file. So if the right Class is found, i induct the setDataArray(StreamReader sr) function from the right Class, to parse the Data Array. (At this point i have to tell you, that i need those different Classes, because i need to upload them to a sql server specificly.)
This static function creates an object of it self and uses the parseLine(String line) Function to fill the object with data from the given line.
WHAT I NEED.
I want to call the static function of any class, just by having the name of this class. So i dont have to use that much code and be able to add more classes.
Later on i want to call every class and use the uploadToServer() to Upload it to the server.
Is this possible?
Since your static method is creating an instance of its class anyway, I suggest a different approach:
Create an interface that all classes that contain ParseLine can implement. (Change out the return type for the correct one):
public interface IParseLine
{
string ParseLine(string line);
}
Have all of the classes that contain ParseLine() implement IParseLine.
Create an instance of the class, cast it to an IParseLine, and execute the method:
IParseLine pl = Activator.CreateInstance(Type.GetType(className)) as IParseLine;
if (pl != null)
{
string parsedString = pl.ParseLine(line);
// ...
}
Edit From comments:
I want to create a while loop, which can be stated as followed:
while{!sr.EndofStream){ line = sr.ReadLine(); for(int i = 0; i <
classNames.length; i++){ if(line.Contains(classNames[i].MYINDICATOR){
CALL classNames[i] STATIC METHOD TO PARSE THE FOLLOWING LINES AND
CREATE DATA Objects of its Class } }
I didn't test this, but you can change the code to something like this (caching the reflection required to get MYINDICATOR):
IList<KeyValuePair<string, Type>> typeIndicators = classNames.Select(x => {
Type t = Type.GetType(x);
string indicator = (string)t.GetField("MYINDICATOR", BindingFlags.Public | BindingFlags.Static).GetValue(null);
return new KeyValuePair(indicator, t);
});
while (!sr.EndOfStream)
{
line = sr.ReadLine();
foreach (var types in typeIndicators)
{
if (line.Contains(types.Key))
{
IParseLine pl = Activator.CreateInstance(types.Value) as IParseLine;
if (pl != null)
{
string parsedString = pl.ParseLine(line);
}
}
}
}
I want to call the static function of any class, just by having the name of this class.
Well, you can use Type.GetType(className) to get a Type (note that the name needs to at least be fully qualified including the namespace, and may also need the assembly name depending on your exact scenario), then Type.GetMethod to get a MethodInfo. Finally, call MethodBase.Invoke to invoke the method.
If you could use typeof(Foo) instead of using a string, it would make the code simpler and more robust.
(Side-note: if your methods are really called parseLine, parseInduction, setDataArray etc, you should consider renaming them to follow .NET naming conventions :)
I think I see where you're coming from. In this simple exmaple below, I have a static class with a method in it (nothing amazing about that).
public static class MyStaticClass
{
public static DateTime GetTime()
{
return DateTime.Now;
}
}
If I want to invoke that method using reflection, I can just use the following code, but it does assume that the MyStaticClass class is available via a reference or inthe same project etc.
MethodInfo method = typeof(MyStaticClass).GetMethod("GetTime");
object result = method.Invoke(null, null);
if (result is DateTime)
{
Console.WriteLine(((DateTime)result).ToLongTimeString());
}
What you seem ot be asking for is a moethod of doing this when you don't have a reference to the class. In which case, try something like this:
MethodInfo method = Type.GetType("PocStaticReflect.MyStaticClass, PocStaticReflect, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null").GetMethod("GetTime");
object result = method.Invoke(null, null);
if (result is DateTime)
{
Console.WriteLine(((DateTime)result).ToLongTimeString());
}
Notice the fully qualified class name!
If you get that working, then you can simply loop though your class names and call the method you desire. Obviously, you'll probably want more error checking and more detail in the GetMethod() calls, but this shlud give you the gist of it. I've done something similar before looping though assemblies in a folder to pickup plug-ins for an application. That time, each of the classes implemented an interface to make them easier to locate, which may be helpful path to follow.
Or try this:
private static object GetResultFromStaticMethodClass(string qualifiedClassName, string method)
{
Type StaticClass = Type.GetType(qualifiedClassName);
MethodInfo methodInfo = StaticClass.GetMethod(method);
object result = methodInfo.Invoke(null, null);
return result;
}
Use:
object result = GetResultFromStaticMethodClass(
"Utilities.StringHelper,DaProject",
"ToList"
);
This call the static method ToList in the StringHelper class, in the Utilities namespace, in the DaProject project (same assembly and project name).
If you need parameters, add them in the second parameter in the methodInfo.Invoke(null, null) call
I need to create the ability to drill through an objects properties like two or three deep. For instance, class A has a property reference to class B, which I need to access class C. What is the best way to do this: straight reflection, or maybe using the TypeDescriptor, or something else?
Thanks.
It's not too hard to write. I put a few classes together to deal with this so I could serialize properties of a WinForm. Take a look at this class and the related classes.
http://csharptest.net/browse/src/Library/Reflection/PropertySerializer.cs
If you know the path in a static context (ie the path is always the same) and the properties are accessible (internal or public) you can use dynamic
[Test]
public void Foo()
{
var a = new A
{
B = new B
{
C = new C
{
Name = "hello"
}
}
};
DoReflection(a);
}
private void DoReflection(dynamic value)
{
string message = value.B.C.Name;
Debug.WriteLine(message);
}
I you wanna write you own serialization code for whatever reason, you'll be using reflection.
What you do is that you write a recursive method of serlizating a type. You then apply this as you see fit to get the result.
var type = myObjectOfSomeType.GetType();
// now depending on what you want to store
// I'll save all public properties
var properties = type.GetProperties(); // get all public properties
foreach(var p in properties)
{
var value = p.GetValue(myObjectOfSomeType, null);
Writevalue(p.Name, value);
}
The implementation of WriteValue have to recognize the built in types and treat them accordingly, that's typical things like string, char, integer, double, DateTime etc.
If it encounters a sequence or collection you need to write out many values.
If it encounters a non trivial type you'll apply this recursive pattern again.
The end result is a recursive algorithm that traverses your object model and writes out values as it encounters types that I know how to serialize.
However, I do recommend looking into WCF, not for building services, but for serialization. It shipped as part of the .NET 3.0 framework with a new assembly System.Runtime.Serilization and in general is very capable when dealing with serialization and data annotations.
Let's say I have base class FooParent, and it has a numerous amount of FooChildren. At runtime I must create an instance of one of the FooChildren. How would I do this? I realize I could create a huge map (and use delegates) or a huge switch/case statement, but that just seems a bit sloppy. In something like PHP, I can easily create a class dynamically like this:
$className="FooClass";
$myNewFooClass=new $className; //makes a new instance of FooClass
(you can also do this using reflection).
Does .NET have anything like this? Is reflection an option, and does it have any performance penalties? If not, what other options do I have?
The type of class will be determined by a JSON request. The variable could be anything I want..it could be an integer if I wanted to do an enum, or it could be the full class name. I haven't created it yet so I'm undecided.
You can do it with reflection if you really want, but there will be performance penalties. Whether they're significant or not will depend on your exact situation.
Depending on exactly what you want to do, I'd quite possibly go with either a switch/case statement or a map, as you suggest. In particular, that would be useful if you need to pass different arguments to different constructors based on the type you're constructing - doing that via reflection would be a bit of a pain in that you'd already be special-casing different types.
EDIT: Okay, so we now know that there will always be a parameterless constructor. In that case, your JSON could easily contain the class name without the namespace (if they're all in the same namespace) and your method could look something like this:
public FooParent CreateFoo(string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
string fullName = "Some.NameSpace." + name;
// This is assuming that the type will be in the same assembly
// as the call. If that's not the case, we can look at that later.
Type type = Type.GetType(fullName);
if (type == null)
{
throw new ArgumentException("No such type: " + type);
}
if (!typeof(FooParent).IsAssignableFrom(type))
{
throw new ArgumentException("Type " + type +
" is not compatible with FooParent.");
}
return (FooParent) Activator.CreateInstance(type);
}
Where do you determine the name to use? If it's passed in somewhere, a switch statement can be very simple when reformatted away from the norm a little:
public FooParent CreateFoo(string name)
{
switch (name)
{
case "Foo1": return new Foo1();
case "Foo2": return new Foo2();
case "Foo3": return new Foo3();
case "Foo4": return new Foo4();
case "FooChild1": return new FooChild1();
default:
throw new ArgumentException("Unknown Foo class: " + name);
}
}
Mind you, having just written that out I'm not sure it has any real benefit (other than performance) over using Type.GetType(name) and then Activator.CreateInstance(type).
How does the caller know the class name to pass in? Will that definitely be dynamic? Is there any chance you could use generics? The more you could tell us about the situation, the more helpful we could be.
As long as all your FooChildren have parameterless constructors, you can do this with reflection.
Activator.CreateInstance<FooChildType>();
If you don't actually have a reference to the type, and all you have is a string with the name of the class, you can do:
Activator.CreateInstance("FooChildClassName", "Fully.Qualified.AssemblyName");
There is a performance penalty with reflection, but I wouldn't get hung up about it if this turns out to be the simplest solution for you, and your performance is acceptable.
yourvar = Activator.CreateInstance(Type.GetType("foo.bar.Baz"));
If you care about performance, there is another option. Use
Type yourType = Type.GetType("FooClass");
to get the type of your class. Now you can use
ConstructorInfo ctor = yourType.GetConstructor(new Type[0]);
to get the constructor info for your constructor. If you don't want the default constructor, pass an array of the types you want to pass to the constructor. Now you can use the constructor like this:
object instanceOfFooClass = ctor.Invoke(new object[0]);
The first two steps have to be executed only once. You can save "ctor" for further use. That should be faster that calling Activator.CreateInstance.