acquire class name from file path - c#

I have a system that reads through a folder and saves the paths to an array list. this folder contains a bunch of class files ".cs" all of these classes implement an interface called BaseScript.
I am attempting to find the class name so that I can call class methods but you are supposed to be able to add class files to this folder on a regular basis, so I cannot hardcode the objects to be created.
e.g. I have a file called "Manufacturing.cs":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LLS
{
class Manufacturing : BaseScript
{
public void init()
{
Console.WriteLine("Manufacturing...");
}
public void uninit() { }
public void recomp() { }
}
}
It implements "BaseScript":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LLS
{
public interface BaseScript
{
void init();
void uninit();
void recomp();
}
}
I need to be able to use the path: "\Scripts\Manufacturing.cs" to call something like
BaseScript[] s = {new "Manufacturing class name"}
I know there must be some roundabout way of doing this.
how can I find the class name and then create an instance from that class?

If your class is in the same assembly then you can create an instance of the object by using Activator.CreateInstance. I didn't try your code on my side. So casting might not work. Double check this code:
BaseScript s = (BaseScipt)Activator.CreateInstance(null, "Namespace.TestClass");

Edit-I mistakenly though you had dlls and not cs files for some reason.
As others say you are not properly explaining the scenario. But from what I understand you are probably implementing a plugin type of pattern here.
In order to call methods on C# classes you may add later on, you need to iterate through the folder, get the *.cs files, compile them and then using reflection, load the assembly and create an instance of a class you know exists(you should know the fully qualified name of the class beforehand). Finally, you should find the method you want to call and then call it using reflection. Here is some code to get you started:
Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.CompilerParameters parameters = new System.CodeDom.Compiler.CompilerParameters();
parameters.GenerateInMemory = true;
//You should add all referenced assembiles needed for the cs file here
//parameters.ReferencedAssemblies.Add();
var files = new System.IO.DirectoryInfo("Scripts").GetFiles("*.cs");
foreach (System.IO.FileInfo file in files)
{
System.CodeDom.Compiler.CompilerResults result =
provider.CompileAssemblyFromSource(parameters, new[] { System.IO.File.ReadAllText(file.FullName) });
object instance = result.CompiledAssembly.CreateInstance(file.Name);
if (instance is BaseScript)
{
//Do processing on (BaseScript)instance
}
}

Related

How can I move code to create a list into a separate class and then call it

Newby c#/asp.net question here. I am creating a website with .aspx pages.
Within a method I have created a list and added items to it as shown below:
var footballTeams = new List<string>();
footballTeams.Add("Arsenal");
footballTeams.Add("Aston Villa");
footballTeams.Add("Bournemouth");
footballTeams.Add("Brentford");
footballTeams.Add("Brighton & Hove Albion");
footballTeams.Add("Chelsea");
However, I want to move this code into its own separate class - so it is easier to update the teams rather than have to go deep into code.
How would I code this in a class and then be able to call and use the list from another class.
I have tried creating a new folder called App_Code. And then putting a dummy method in it as shown below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FootballResultPredictor.App_Code
{
public class Class1
{
public static String MyMethod()
{
string myString = "test";
return myString;
}
}
}
However when I try to call the method from the other class, it just can't seem to find it at all as shown here:
Below is the file structure:
I am trying to call a method in Class1.cs from StartNewSeason.aspx
Looking quickly at your code, I have some comments.
-Don't put your new class in a separate folder.
-This code is wrong: string a=myMethod();
because you can't call a method before you have an instance (new...) of a class unless the class is a static class, which is not the case here.
-Coding string b=Class1.MyMethod(), is better, but still wrong, since Class1 is the name of the class not the name of the object.
At this point, I guess the concept of the class and the class object are somewhat not very clear to you.
I suggest that you review this fundamental concept as it is the core of Object Oriented Programming. Also using ASP.NET at this point of your learning path is highly not advisable, I highly recommend that you get to learn OO fundamentals through C# console applications or Windows Forms. These two frameworks, are much simpler to deal with.
When you create a class (of .cs type) file under the same solution in VS it would have a namespace and a class definition. If the class is not static, you refer to it as (other ways can be used as well):
myClassName ObjectName = new myClassName();
The namespace can be specified if the class is in a different project, like new NameSpace2.myClassName, but this is not the case here.
Only after you create an instance (an object) of the non-static class, you can use the object and its method using the ObjectName (not the myClassName). For exmaple:
ObjectName.MethodName();
Back to the program at hand, here is one way to have a separate class handle the list. There are many ways to do this, this way provides validation and allows you to iterate over the list items. Let me know if this is not clear.
The new class is here:
//using System;
//using System.Collections.Generic;
//using System.Data;
public class FootballTeams
{
public List<string> footballTeams = new List<string>();
public FootballTeams()
{
//initialize the list
this.AddFootballTeam("Arsenal");
this.AddFootballTeam("Aston Villa");
this.AddFootballTeam("Bournemouth");
this.AddFootballTeam("Brentford");
this.AddFootballTeam("Brighton & Hove Albion");
this.AddFootballTeam("Chelsea");
}
//Method to add a new team
public void AddFootballTeam(string parmTeam)
{
//validate input
if (string.IsNullOrWhiteSpace(parmTeam))
{ throw new NoNullAllowedException("Error:Team name is empty"); }
if (footballTeams.Contains(parmTeam))
{ throw new DuplicateNameException(); }
//if valid add the name to the list
footballTeams.Add(parmTeam);
}
}
A sample usage of the above class is:
var _t = new FootballTeams();
try
{
_t.AddFootballTeam("Ringers");
}
catch (Exception _ex)
{
Console.WriteLine(_ex.Message);
return;
}
foreach (var _team in _t.footballTeams)
{
Console.WriteLine(_team);
}

Namespace and class have the same name

I have inherited a large c# project. One of the classes has a namespace and class which share the same name. As a result when making an instance of the class i have to do this:
using xxx.existingName
IinterfaceName dog = new existingName.existingName();
Since the existing class has an interface i am able to avoid having existingName.existingName on the left of the =. Using var dog would also do this. However i also want to avoid existingName.existingName being used on the right hand side because it is less readable.
Is there any way to do this without renaming the existing code?
You could rename the class or the namespace via the using directive:
using ClassAlias = Test.Test;
using NamespaceAlias = Test;
public class Program
{
public static void Main()
{
ClassAlias a = new ClassAlias();
NamespaceAlias.Test t = new NamespaceAlias.Test();
}
}
namespace Test{
public class Test{}
}
You could use an alias to make this more readable(well, not with these names):
using AliasForName = existingName;
...
IinterfaceName dog = new AliasForName.existingName();
If the original author would have looked at this MSDN article, he would have used a different name in the first place:
X DO NOT use the same name for a namespace and a type in that
namespace . For example, do not use Debug as a namespace name and then
also provide a class named Debug in the same namespace. Several
compilers require such types to be fully qualified.
By the way, you should really apply capitaliation conventions.

Why can't i use partly qualified namespaces during object initialization?

I suspect this is a question which has been asked many times before but i haven't found one.
I normally use fully qualified namespaces if i don't use that type often in the file or i add using namaspacename at the top of the file to be able to write new ClassName().
But what if only a part of the full namespace was added ? Why can't the compiler find the type and throws an error?
Consider following class in a nested namespace:
namespace ns_1
{
namespace ns_1_1
{
public class Foo { }
}
}
So if i now want to initialize an instance of this class, it works in following ways:
using ns_1.ns_1_1;
public class Program
{
public Program()
{
// works, fully qualified namespace:
var foo = new ns_1.ns_1_1.Foo();
// works, because of using ns_1.ns_1_1:
foo = new Foo();
}
}
But following doesn't work:
using ns_1;
public class Program
{
public Program()
{
// doesn't work even if using ns_1 was added
var no_foo = new ns_1_1.Foo();
}
}
it throws the compiler error:
The type or namespace name 'ns_1_1' could not be found (are you
missing a using directive or an assembly reference?)
I assume because ns_1_1 is treated like a class which contains another class Foo instead of a namespace, is this correct?
I haven't found the language specification, where is this documented? Why is the compiler not smart enough to check if there's a class or namespace(-part)?
Here's another - less abstract - example of what i mean:
using System.Data;
public class Program
{
public Program()
{
using (var con = new SqlClient.SqlConnection("...")) // doesn't work
{
//...
}
}
}
Edit: now i know why this seems very strange to me. It works without a problem in VB.NET:
Imports System.Data
Public Class Program
Public Sub New()
Using con = New SqlClient.SqlConnection("...") ' no problem
End Using
End Sub
End Class
This obvious way unfortunately not working but you can make all this by an alias namespace:
using ns_1_1 = ns_1.ns_1_1;
public class Program
{
public Program()
{
var no_foo = new ns_1_1.Foo();
}
}
The documentation says:
Create a using directive to use the types in a namespace without having to specify the namespace. A using directive does not give you access to any namespaces that are nested in the namespace you specify.
So the using only includes the types (not the namespaces) that are defined in the specified namespace. In order to access types of nested namespace you need to specify it explicitly with a using directive as you did in your first example.
This is documented in the standard in 3.8 Namespace and Type Names, but it's a bit convoluted to follow.
The gist of it that a partial namespace reference is only looked for in the namespace where it occurs, and each layer outwards. using-directives are not checked.
In your example, ns_1_1.Foo would be found if Foo is found anywhere in:
Program.Program.ns_1_1.Foo
Program.ns_1_1.Foo
ns_1_1.Foo
Partial namespaces will work only if your current class is part of that partial namespace. Using statements are not considered for accessing types through partial namespace.
For instance this will work because your current namespace is ns_1
namespace ns_1
{
public class Program
{
public Program()
{
var no_foo = new ns_1_1.Foo();
}
}
}

Do you have to instantiate [RunInstaller(true)]-classes?

I found this code sample on MSDN website. My question is regarding the last line where they instantiate the class in the main method. But is that necessary? According to the documentation on Installutil:
Installutil.exe uses reflection to inspect the specified assemblies
and to find all Installer types that have the
System.ComponentModel.RunInstallerAttribute attribute set to true. The
tool then executes either the Installer.Install or the
Installer.Uninstall method on each instance of the Installer type.
So does it mean that the main method and the instantiation of the MyEventLogInstaller-class is not necessarty?
using System;
using System.Configuration.Install;
using System.Diagnostics;
using System.ComponentModel;
[RunInstaller(true)]
public class MyEventLogInstaller: Installer
{
private EventLogInstaller myEventLogInstaller;
public MyEventLogInstaller()
{
// Create an instance of an EventLogInstaller.
myEventLogInstaller = new EventLogInstaller();
// Set the source name of the event log.
myEventLogInstaller.Source = "NewLogSource";
// Set the event log that the source writes entries to.
myEventLogInstaller.Log = "MyNewLog";
// Add myEventLogInstaller to the Installer collection.
Installers.Add(myEventLogInstaller);
}
public static void Main()
{
MyEventLogInstaller myInstaller = new MyEventLogInstaller();
}
}

how to use a new class method in other apps?

I used this code in c++ to use a class (that I defined before)in my other Apps.
#include class_name ;
How can I define a public class that could be used in all apps?
Thanks
To access classes from external assemblies you must add a reference to an external assembly. This will allow you to access public classes from the external assembly.
To specify a class from a namespace outside your current scope you must prefix the class's type specifier with its namespace name. To avoid this overhead, you can "include" the external namespace with the using directive.
Multiple namespaces can exist within a single assembly.
Assembly Fruit:
namespace Common
{
public class Strange
{
var mystery = new Mystery() // Won't compile, no reference to Mystery.
}
}
namespace Fruit
{
public class Orange
{
}
}
Assembly Vegetables:
References Fruit
namespace Common
{
public class Mystery
{
}
}
namespace Fungi
{
public class Mushroom
{
}
}
namespace Vegetables
{
using Common;
public Class Carrot
{
var strange = new Strange() // Compiles correctly.
var mystery = new Mystery() // Compiles correctly.
var orange = new Orange() // Won't compile, what's an Orange?
var orange = new Fruit.Orange() // Compiles correctly.
var mushroom = new Mushroom() // Won't compile, what's a Mushroom?
var mushroom = new Fungi.Mushroom() // Compiles correctly.
}
}
You need to create a Class Library project, which compiles to a DLL file.
You can then add a reference to it in other projects.
You have to include the namespace as below and also add any references if in another project.
using class_namespace;
If the other class is public or internal (and in the same assembly if they are internal), is in the same project, and has the same namespace, then you don't need to do anything at all. You will be able to refer to the other class by just using it's class name.
If they are in different namespaces then you can use a using statement (at the top of the file) to bring the other namespace into scope, or you can refer to the other class using the fully qualified name (i.e. OuterNamespace.InnerNamespace.ClassName) every time you use the class. (Which almost nobody ever does, everyone just uses using statements because they are so much more convenient.)
If the class is in another project entirely then you will need to add a reference to that class through visual studio. If you are creating a project that is designed to be referenced by other projects then it's project type should be a "class library".
Every class is created under a namespace
namespace abc{
public MyClass{
//functionality
}
}
To use your class on a different application,you need to import the namespace.
using abc;
public class usingClass{
MyClass obj = new MyClass();
}

Categories