Instantiating a class in C# from a string - c#

I'm working on a windows phone 7 application which uses Silverlight. What I'm looking to do is create a new instance of a class given a string containing the name of the correct class I would like to create. Below is the snipit of code I'm referring to and I am trying to use it to create the new instance. I know from debugging that serviceClass contains the correct string and if I add ".cs" to it, it would now correspond directly to one of the classes I have, so why isn't it being created?
WebViewService foundService; //From above
....
....
services.TryGetValue(mode, out foundService); //Find service
if (foundService == null)
{
string serviceClass;
serviceRegistry.TryGetValue(mode, out serviceClass); //Find serviceClass
if (serviceClass != null) //create new web service if one is found
{
try
{
//TODO: This is not working properly, should create an instance of some child class of WebViewService
foundService = (WebViewService)System.Activator.CreateInstance(Type.GetType(serviceClass+".cs"));
services.Add(mode, foundService);
}
catch
{
//But instead it always ends up here with ArgumentNullExeption
}
}
}
return foundService;
}
Any help at all or any suggestions would be greatly appreciated. Thanks for your time!

If your string contains fully qualified type name then you can create instance.

Try using the full name of the class (namespace included), without the ".cs" part. For example: YourApp.Services.YourWebViewService

Type.GetType doesn't take a string with a file name. It takes a class name or a struct name.

Related

What parameter i have to assign inside my variable so i can start it from my Main?

im new to C# and Tia Openness and have an problem. I dont know what parameter goes inside my ImportSingleTextList();.Its an example from Siemens but there is never mentioned how to call it inisde the main. That is my code.
private static void ImportSingleTextList(HmiTarget hmitarget)
{
TextListComposition textListsComposition = hmitarget.TextLists;
IList<TextList> importedTextLists = textListsComposition.Import(new FileInfo(#"D:\SamplesImport\myTextList.xml"), ImportOptions.Override);
}
I guess you have to look into your HmiTarget exactly. Is it a class, then you should instantiate a first instance of it; what constructor does this class have - with or without parameters? Click on HmiTarget and see what input it expects.
I guess you class has some kind of enumerable hmitarget.TextLists that you have to fill or get too.
Presumably you have a Project instance. You have to drill down from Project->Device->DeviceItem(->DeviceItem) until you find a DeviceItem that can provide a SoftwareContainer service. It may be that all such DeviceItems reside at the first level below Device; I haven't checked. Anyway, here's a method I wrote that searches the first and second DeviceItem levels:
public static HmiTarget GetHmiTarget(Device hmiDevice)
{
//search first level of DeviceItems
foreach (DeviceItem di in hmiDevice.DeviceItems)
{
SoftwareContainer container =
di.GetService<SoftwareContainer>();
if (container != null)
{
HmiTarget hmi = container.Software as HmiTarget;
if (hmi != null)
return hmi;
}
//search second level of DeviceItems
foreach (DeviceItem devItem in di.DeviceItems)
{
SoftwareContainer subContainer = devItem.GetService<SoftwareContainer>();
if(subContainer != null)
{
HmiTarget hmi = subContainer.Software as HmiTarget;
if (hmi != null)
return hmi;
}
}
}
return null; //nothing was found at the first or second levels
}
to get the Device, you can use PROJECT.Devices.Find(NAME) where PROJECT is your TIA portal project instance, and NAME is the string name of your HMI device.

How to incorporate a variable into a URI?

Basically I'm trying to put a result of a query into a file path, into the image source.
Updated code. Now I actually get the string I want but I still have trouble with interpolating it into the Uri constructor.
Random rand = new Random();
var nrand = rand.Next(1, 4);
using (var db = new DungeonContext())
{
var query = db.Rooms.Where(b => b.RoomId == nrand).Select(b => b.RoomName);
foreach(string name in query)
{
nameOfRoom = name;
}
}
Somehow I have trouble setting images dir as Resources since I'm missing advancent properties for this folder.
roomScreen.Source = new BitmapImage(new Uri($"/images/{nameOfRoom}.png", UriKind.Relative));
Making Uri relative seemed to stop throwing exceptions, but the intended effect does not happen.
The way you're creating the URI is correct. The trouble is that you're trying to use what is likely meant to be readable text (the name of a room) in a URI and as a flle name. You didn't specify what nameOfRoom is, so I can't tell exactly why it's invalid.
There are ways around it. You could look at this answer which explains how to remove invalid characters from a file name.
But the best solution is not to have the problem. Don't use the name of the room as a file name. Your question indicates that a room has an ID, which is apparently an integer. Using that instead would be much easier:
using (var db = new DungeonContext())
{
room = db.Rooms.Where(b => b.RoomId == nrand);
}
and then
roomScreen.Source = new BitmapImage( new Uri($"/images/Room{room.RoomId}.png"));
If you want to use your code as-is, that's possible. When you do this:
nameOfRoom = db.Rooms.Where(b => b.RoomId == nrand).ToString();
you're calling ToString() on what is presumably a Room class. Unless you override that method, the result will always be the name of the class. (So it would be the same for every room.)
If you overrode the ToString method:
public override string ToString()
{
return $"Room{RoomId}";
}
then calling room.ToString() would return "Room1" or "Room2", etc.
String interpolation calls ToString(), so in that case you could just do
roomScreen.Source = new BitmapImage( new Uri($"/images/{room}.png"));
That works. One downside is that it's not explicit. Someone reading that line of code might not know that Room.ToString() is also the value used to create a file name. You might also want to use the ToString() method differently.
If you wanted to be really explicit and clear, you could create an extension method like this:
public static class RoomFileNameExtensions
{
public static string GetImageFileName(this Room room)
{
return $"Room{room.RoomId}.png";
}
}
Now the Room class isn't responsible for knowing how file names are created. You could do this:
roomScreen.Source = new BitmapImage( new Uri($"/images/{room.GetImageFileName()}"));
You can use that both when creating the file and when reading the file. It ensures that both operations will determine the file name the same way.
Apparently all I needed to do was add UriKInd.RelativeOrAbsolute to the constructor.
If it's in the project directory, utilizing the System.IO.Path namespace comes to mind - something like
Path.Combine(Environment.CurrentDirectory, $"/images/{nameOfRoom}.png")

Use variable value to check if particular instance exists, if not - create it

I have a list of images like this:
public List<Image> imageList = new List<Image>();
I also have a picture class in order to collect and manipulate data about the images in the list:
public Class Pic {
// properties and stuff
}
And then I have a function that takes an integer as an argument. That integer corresponds to an image in the image list. What I want to do in the function is to check if an instance of the Pic class has been created for that particular image. If not, I want to create it, using the value of the variable passed into the function. The following code obviously doesn't work, but it shows what I want:
public void doStuffWithImage(int picNumber) {
// Check if instance called pic + picNumber exists
if(pic + picNumber.toString() == null) {
// Create an instance
Pic pic + picNumber.toString() = new Pic();
}
}
Suggestions on how to accomplish this?
It seems like you're trying to create individual variables pic1, pic2, etc. you'd be better off using a dictionary:
Dictionary<int, Pic> pics = new Dictionary<int, Pic>();
public void doStuffWithImage(int picNumber) {
// Check if instance called pic + picNumber exists
if(!pics.ContainsKey(picNumber)) {
// Create an instance
pics[picNumber] = new Pic();
}
}
You need to create a "registry" of known Pics. DIctionary<int,Pic> would be good collection to hold this registry. You need to store the registry itself somewhere - perhaps in the "factory" object that registers your pictures.
class PicFactory {
private readonly IDictionary<int,Pic> knownPics = new Dictionary<int,Pic>();
public Pic GetOrCreate(int id) {
Pic res;
if (knownPics.TryGetValue(id, out res)) {
return res;
}
res = new Pic(id.ToString()); // This assumes that Pic(string) exists
knownPics.Add(id, res);
return res;
}
}
This way of implementing a registry may be too primitive for your purposes - for example, if you need your registry to be concurrent, you would need to set up some sort if a locking scheme to protect the knownPics dictionary. The class that accesses pictures would need to create an instance of PicFactory, so that it could access pictures through the GetOrCreate(id) call.
If you are using .net 4.0 or more you can use Lazy type which:
Provides support for lazy initialization.
Which means that the object will be constructed not in the moment of declaration, but when first accessed.
So you can basically declare them like
List<Lazy<Pic>> ....
See Lazy<T> and the Lazy Loading Pattern in general - this is actually a common optimization technique as it defers what can add up to a lot at startup to microdelays during runtime.
Be wary about making sure the microdelays are worth it, and I advise leaving methods about which can force loading.
If you're grabbing from a list, preface with a .Any or .Contains check, and since you're looking up by name like that, consider using a Dictionary instead

How can I move this function into a Class

public string F03_veri_textbox(string veriadi3)
{
string Veritext;
Veritext = webBrowser_sample.Document.GetElementById(veriadi3).GetAttribute("value");
return Veritext;
}
I have a webBrowser_sample object in Form1. I use this function to collect data from specific webpage. It is working properly.
I want to use this function from a class.
But when I try to move it, C# says "The name 'webBrowser_sample' does not exist in the current context".
If I define a new webBrowser_sample in the Class, it will create new webBrowser_sample object.
So I can't use it because I use this function to collect data while I am surfing this browser.
Replace 'mytype' with the object type that webBrowser_sample is. You need to pass in a reference to the object, as in the code below. Another option would be to use an extension method.
public string F03_veri_textbox(string veriadi3, mytype browser)
{
string Veritext;
Veritext = browser.Document.GetElementById(veriadi3).GetAttribute("value");
return Veritext;
}

c# class in a session state?

My senior project is building a reservation system in ASP.NET/C#. Part of my senior project is to have c# classes (and basically use everything ive learned in the past few years). One thing Im trying to do is after I instantiate a new "user" class I need it to travel between the pages. I know session states holds variables, so I figured a session state would work where I can simply type "Session["blah"]." and have access to its members. But I dont see that happening. I realize session states are HTTP context, so i doubted it would work anyway. But is there any other way in which I can accomplish what I need without instantiating a new user class every time? I know its a webpage...but im also trying to make it as much as a functional online program as I can.
Just for coder's sake, heres the code snippet im working with:
cDatabaseManager cDM = new cDatabaseManager();
string forDBPass = Encryptdata(pass_txt.Text.ToString());
string fullName = fname_txt.Text.ToString() + " " + lname_txt.Text.ToString();
cDM.regStudent(email_txt.Text.ToString(), forDBPass, fullName, num_txt.Text.ToString(), carrier_ddl.SelectedValue.ToString(), this);
//ADD - getting a cStudent
cUser studentUser = new cStudent(fullName, forDBPass, email_txt.Text.ToString());
//ADD - session states
Session["cStudent"] = studentUser;
//Session["cStudent"]. //session state will not work with what I am doing
//ADD - transfer to campus diagram
Thanks in advance!!
EDIT:
I want to thank all of you who posted and commented! Ive learned alot from this short discussion. All your answers helped me understand!
From your comment:
The issue is when I type "Session["cStudent"]." I don't have access to my functions. Example: Session["cStudent"].getName() does not give my functionality.
This is because the [] indexer for Session sets/returns objects. The compiler does not know that you stored a cUser object and so you can't access the properties directly without a cast:
string name = ((cUser)Session["cStudent"]).getName();
There are two things that could go wrong here:
If Session["cStudent"] is null you will get a NullReferenceException
If Session["cStudent"] is not really a cUser you will get an InvalidCastException
You should check these conditions and react appropriately if one of them is true.
Also, as others have pointed out, the cUser class needs to be marked as Serializable in order to be stored in Session state.
Session stores item as objects. As long as your class inherits from Object (which it does) you can store it there. Quick caveat, it stores that object using Serialization, so your class must be serializable.
Add a property to your class like so:
public cStudent CurrentStudent
{
get {
if(Session["CurrentUser"] == null)
return null;
return (cStudent)Session["CurrentUser"];
}
set {
Session["CurrentUser"] = value;
}
}
When retrieving an object value from session state cast it to appropriate type.
[Serializable]
public class student
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
In Page1:
student s1 = new student();
s1.FirstName ="James";
s1.LastName = "Bond";
Session["blah"] = s1;
And when you want to access Session["blah"] in page 2
student s2 = (Session["blah"] !=null ? (student)Session["blah"] : null);
Now you can access properties of s2 as s2.FirstName, s2.LastName

Categories

Resources