Visual Studio Method Call Flow Dump - c#

I would like to list down the method call sequence from top to bottom in my .net project.
using System;
public class Program
{
public static void Main()
{
One();
}
public static void One(){
Two();
}
public static void Two(){
Three();
}
public static void Three(){
Four();
}
public static void Four(){
Console.WriteLine("Hello World!");
}
}
In the above sample class I required to get the log like
"Main()->One()->Two()->Three()->Four()"

you can use System.Diagnostics.StackTrace to get the current stackTrace and use it to log the required:
Demo as per your code:
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
One();
}
public static void One(){
Two();
}
public static void Two(){
Three();
}
public static void Three(){
Four();
}
public static void Four(){
Console.WriteLine("Hello World!");
var stackTrace = new System.Diagnostics.StackTrace();
List<string> methods = new List<string>();
for (int i = stackTrace.FrameCount - 1; i >= 0; i--)
{
methods.Add($"{stackTrace.GetFrame(i).GetMethod().Name}()");
}
Console.WriteLine(string.Join("->", methods));
}
}
The above code prints the output as
Main()->One()->Two()->Three()->Four()
Check the fiddle - https://dotnetfiddle.net/Ee8ni8

There is one non-ideal solution:
Prepare a set of test cases that will run your program methods in as many combinations as possible, and so provide good code coverage.
Manually add a stack trace logging functionality at the beginning of each method's body and adjust stack trace logging format to your needs (Main()->One()...). This could be done with System.Diagnostics.StackTrace, as user1672994 pointed out.
Filter your stack trace log so that it contains only stack traces which are not prefix of any other stack traces, thus leaving off incomplete paths.
You could also discover the call flow from Call Hiearchy window in Visual Studio, but it doesn't give you the data in requested format. It will however find call flows independently of your possibly imperfect test cases.
See also: Visual Studio Call Hierarchy View: call it programmatically

Related

c# cannot access class because of protection level

hey guys I'm new to C# and I was practicing classes and methods and that stuff and I did the following code:
using System;
namespace ConsoleApp6
{
class Book
{
static void Review()
{
int x = 10;
Console.WriteLine(x);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Book.Review);
}
}
}
It's really simple but when i ran it in said that it can't access the "Review" method because of it's protection level, please help
The reason for this error is that the default access modifier for methods is private, which means that only members of the same class can see them.
Since you want to reference the method from another class in the same namespace, you need to give broader access to the method by changing the access modifier to either internal (which means any classes in the same assembly can see it) or public (which means it can be seen by everybody).
Either one of these should solve your problem:
// Only members of the same assembly can access this method
internal static void Review() { // code omitted }
// Everyone can access this method
public static void Review() { // code omitted }
You can read more about access modifiers here.
Additionally, you have set the return value of Review to void, and are then trying to pass this to the Console.WriteLine() method, which expects an actual type. This will result in a compile error (something like: "cannot convert void to [someType]").
In order to solve this you could either just call the method from main and let the method write to the console:
private static void Main(string[] args)
{
Book.Review();
}
Or, my preference would be to have the method return a string, and then write that to the console in the Main method (I prefer this because it makes the method more versatile - someone could call it to simply retrieve a review without displaying it to the console, for example):
public static string Review()
{
int x = 10;
return x.ToString();
}
Note that when you call the method, you will need to include the parenthesis after the name:
private static void Main(string[] args)
{
Console.WriteLine(Book.Review());
}

C# - calling one method inside another within the same class

I have 2 methods:
static int CalculateParity(string encodedHamming, int parityBit)
{
//Code here
}
static string CalculateHamming(string rawByte)
{
//Code here
}
Inside the main method (all of these are in the same class) I want to call the first two methods. I understand normally it would be
CalculateHamming();
CalculateParity();
To call them, however I'm not sure how to call them because the methods have definitions. I had a look around stack overflow and other sites but I can't find anything. If someone could explain to me how to do this or link me to something similar I may have missed that would be great, thanks!
You have to use ClassName.MethodName so if the class was called Calculations, like below:
static class Calculations
{
static int CalculateParity(string encodedHamming, int parityBit)
{
//Code here
}
static string CalculateHamming(string rawByte)
{
//Code here
}
}
Inside main would be like:
main()
{
string rawBtye;
Calculations.CalculateHamming(rawBtye);
}
If you want to call CalculateParity inside CalculateHamming you don't need the ClassName before:
static string CalculateHamming(string rawByte)
{
CalculateParity(encodedHamming, parityBit);
}
I think you should first get some clue about the basic concepts.
here methods/functions
and here classes
Your program's structure should be something similar to this:
class Program
{
static void Main(string[] args)
{
}
void Function1()
{
}
void Function2()
{
}
}
Nonetheless, I advise you learning the concepts first, then solving your particular issue.

Static Variable Null In Method Call, But Initialized In Program

I have a bit of a head-scratcher here that I wonder if someone may know the answer to.
The setup is basically this:
//in Visual Studio plug-in application
SpinUpProgramWithDebuggerAttached();
//in spun up program
void Start()
{
StaticClass.StaticVariable = "I want to use this.";
XmlSerializer.Deserialize(typeof(MyThingie), "xml");
}
class MyThingie : IXmlSerializable
{
ReadXml()
{
//why the heck is this null?!?
var thingIWantToUse = StaticClass.StaticVariable;
}
}
The problem that has me pulling my hair out is that StaticClass.StaticVariable is null in the IXmlSerializable.ReadXml() method, even though it's called RIGHT AFTER the variable is set.
Of note is that breakpoints aren't hit and Debugger.Launch() is ignored in the precise spot the problem occurs.
Mysteriously, I determined through raising exceptions that the AppDomain.CurrentDomain.FriendlyName property is the same for the place the static variable is populated vs. null!
Why the heck is the static variable out of scope?!? What's going on?!? How can I share my variable?
EDIT:
I added a static constructor, per a suggestion in the responses, and had it do a Debug.WriteLine. I noticed it was called twice, even though all the code appears to be running in the same AppDomain. Here is what I see in the output window, which I'm hoping will be a useful clue:
Static constructor called at: 2015-01-26T13:18:03.2852782-07:00
...Loaded 'C:...\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'...
...Loaded 'Microsoft.GeneratedCode'...
...Loaded 'C:...\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'....
...Loaded 'C:\USERS...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO\12.0EXP\EXTENSIONS...SharePointAdapter.dll'. Symbols loaded.
...Loaded 'Microsoft.GeneratedCode'.
Static constructor called at: 2015-01-26T13:18:03.5196524-07:00
ADDITIONAL DETAIL:
Here is the actual code, since a couple of commenters thought it might help:
//this starts a process called "Emulator.exe"
var testDebugInfo = new VsDebugTargetInfo4
{
fSendToOutputWindow = 1,
dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess,
bstrArg = "\"" + paramPath + "\"",
bstrExe = EmulatorPath,
LaunchFlags = grfLaunch | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_WaitForAttachComplete,
dwDebugEngineCount = 0,
guidLaunchDebugEngine = VSConstants.CLSID_ComPlusOnlyDebugEngine,
};
var debugger = Project.GetService(typeof(SVsShellDebugger)) as IVsDebugger4;
var targets = new[] { testDebugInfo };
var processInfos = new[] { new VsDebugTargetProcessInfo() };
debugger.LaunchDebugTargets4(1, targets, processInfos);
//this is in the emulator program that spins up
public partial class App : Application
{
//***NOTE***: static constructors added to static classes.
//Problem still occurs and output is as follows (with some load messages in between):
//
//MefInitializer static constructor called at: 2015-01-26T15:34:19.8696427-07:00
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.0609845-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.3399330-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
protected override void OnStartup(StartupEventArgs e)
{
//...
//initializes a MEF container singleton (stored as static variable)
MefInitilizer.Run();
//here's where it blows up. the important details are that
//FullSelection implements IXmlSerializable, and its implemention
//ends up referencing the MEF container singleton, which ends up
//null, even though it was initialized in the previous line.
//NOTE: the approach works perfectly under a different context
//so the problem is not the code itself, per se, but a problem
//with the code in the environment it's running in.
var systems = XmlSerialization.FromXml<List<FullSelection>>(systemsXml);
}
}
public static class MefInitilizer
{
static MefInitilizer() { Debug.WriteLine("MefInitializer static constructor called at: " + DateTime.Now.ToString("o")); }
public static void Run()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
var container = new CompositionContainer(catalog);
ContainerSingleton.Initialize(container);
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
Debug.WriteLine("ContainerSingleton static constructor called at: " + DateTime.Now.ToString("o") + ". Type: " + typeof(ContainerSingleton).AssemblyQualifiedName);
}
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
}
Bear in mind I've just copied your code to try to replicate your problem.
When running this code, I get a NullReferenceException on Debug.Write, AnotherClass hasn't properly initialized before the call is resolved.
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
However, when I add static constructors to all classes with static fields it works as expected:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
static MefInitilizer()
{
}
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
}
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
I'd say this could definitely be a BeforeFieldInit problem.
As I understood, your code is an plug-in for a Visual Studio, and the main problem of your application is that your class is being instantiated twice, once for a normal AppDomain, and once for some other reason you can't really find out.
First of all, I see here a potential sandboxing from a Visual studio - it wants to test your code in various sets of rights to ensure your code won't harm any other parts of the Visual Studio or end user work. In this case your code could be loaded into another AppDomain, without some rights (You can find a good article at the MSDN), so you can understand why is your code called twice per application.
Second, I want to point out that you are misunderstanding the idea of static constructor and static method:
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
is not the same as
public static ContainerSingleton()
{
compositionContainer = container;
}
So, I suggest you to move the all initialization logic into a static container, something like this:
public class ContainerSingleton
{
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static ContainerSingleton()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
compositionContainer = new CompositionContainer(catalog);
}
}
Second approach: I want to point out that the pattern you use for getting the singleton is outdated, try to use the Lazy<T> class, something like this:
public class ContainerSingleton
{
private static Lazy<CompositionContainer> compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
return compositionContainer.Value;
}
}
public static ContainerSingleton()
{
compositionContainer = new Lazy<CompositionContainer>(() => Initialize());
}
public static void Initialize()
{
// Full initialization logic here
}
}
Also, you should remember that simply adding the empty static constructors isn't enough - you should move all assignments to it, so you should replace such code:
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
with this one:
public class AnotherClass
{
static AnotherClass()
{
Test = ContainerSingleton.ContainerInstance;
}
public static String Test;
}
Update:
#Colin You can even use [LazyTask type][https://msdn.microsoft.com/en-us/magazine/dn683795.aspx] - simply pass a Func to your constructor, and it will be a thread-safe approach, see more in the article. The same Id of the AppDomain means nothing - the sandbox could run your code via AppDomain.ExecuteAssembly method (it's obsolete in 4.5, but still could be a possible variant) to see how it behaves in various set of permissions.
May be there is another technique for this in .NET 4.5, but can't find an article related right now.
Update 2:
As I can see in your code, you are reading some information from disk. Try to add a Code Access Security rule for this to see, if your code is being ran under restricted permissions, like this:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\\example\\out.txt");
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
More about FileIOPermission Class on MSDN.
Try adding a static constructor to ContainerSingleton. I believe this is BeforeFieldInit raising its ugly head again.
Thanks to all who offered suggestions! I never did figure out exactly what was going on (and will continue to investigate/post updates if I ever do), but I did end up coming up with a workaround.
A few suggested that initialization of the static class be internalized, but due to the nature of the actual problem, initialization logic had to be externalized (I was basically loading a DI/service location container whose composition varied from environment to environment).
Also, I suspect it wouldn't have helped, since I could observe that the static constructor was called twice (thus, whatever initialization logic there was would just be called twice, which didn't directly address the problem).
However, the suggestion got me on the right track.
In my case, none of the services I loaded needed to be stateful, so it didn't really matter that the initialization happened twice aside from the performance hit.
Therefore, I simply had the static class check if the MEF container was loaded, and if it wasn't I'd read a configuration file which specified a class that handled initialization.
By doing so, I could still vary the composition of the MEF container from environment to environment, which is currently working pretty well, even if it's not an ideal solution.
I'd like to split the bounty between all who helped, but since that doesn't appear to be possible, I will probably reward OakNinja since he was a hero in spitting out as many good ideas as could realistically be expected given the information I provided. Thanks again!

How to create predictable output with a Lazy<StackFrame>

I'm working on some internal logging framework and for the sake of performance it seems a good idea to lazily get a StackFrame. I want to use this StackFrame to get the first method outside my logging framework.
My initial idea was this:
using System;
using System.Diagnostics;
using NUnit.Framework;
[TestFixture]
public class Test
{
[Test]
public void Caller()
{
NeedsToNowCaller();
}
public void NeedsToNowCaller()
{
Processor.GetName(() => new StackFrame(4));
Really();
Assert.AreEqual("Caller", Processor.stackFrame.Value.GetMethod().Name);
}
public void Really()
{
Assert.AreEqual("Caller",Processor.stackFrame.Value.GetMethod().Name);
}
}
public static class Processor
{
public static Lazy<StackFrame> stackFrame;
public static void GetName(Func<StackFrame> stackFrameProvider)
{
stackFrame = new Lazy<StackFrame>(stackFrameProvider);
}
}
But when you swap these lines:
Really();
Assert.AreEqual("Caller", Processor.stackFrame.Value.GetMethod().Name);
Results are unpredictable, since the call stack is changed. Is there anyway to get a hook to the local scope/frame through a closure, while retaining the laziness.
The only solution i can think of is stepping through the StackTrace, until i detect the first frame with a unknown method.
I really hope there's a better solution.
I don't know that this is much better, but instead of looking for an unknown method, it might be simpler to look for a different source class. This is a bit rough, but would something like this work to give you the last frame before entering the logging class without having to maintain a list of "known" method names (assuming the logging method is not a static...)?
public void DoStuff()
{
int index = 0;
StackFrame frame = new StackFrame(index++);
while (this.GetType().Name.Equals(frame.GetMethod().DeclaringType.Name))
{
frame = new StackFrame(index++);
}
//...
}

Can I add extension methods to an existing static class?

I'm a fan of extension methods in C#, but haven't had any success adding an extension method to a static class, such as Console.
For example, if I want to add an extension to Console, called 'WriteBlueLine', so that I can go:
Console.WriteBlueLine("This text is blue");
I tried this by adding a local, public static method, with Console as a 'this' parameter... but no dice!
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
This didn't add a 'WriteBlueLine' method to Console... am I doing it wrong? Or asking for the impossible?
No. Extension methods require an instance variable (value) for an object. You can however, write a static wrapper around the ConfigurationManager interface. If you implement the wrapper, you don't need an extension method since you can just add the method directly.
public static class ConfigurationManagerWrapper
{
public static ConfigurationSection GetSection( string name )
{
return ConfigurationManager.GetSection( name );
}
.....
public static ConfigurationSection GetWidgetSection()
{
return GetSection( "widgets" );
}
}
Can you add static extensions to classes in C#? No but you can do this:
public static class Extensions
{
public static T Create<T>(this T #this)
where T : class, new()
{
return Utility<T>.Create();
}
}
public static class Utility<T>
where T : class, new()
{
static Utility()
{
Create = Expression.Lambda<Func<T>>(Expression.New(typeof(T).GetConstructor(Type.EmptyTypes))).Compile();
}
public static Func<T> Create { get; private set; }
}
Here's how it works. While you can't technically write static extension methods, instead this code exploits a loophole in extension methods. That loophole being that you can call extension methods on null objects without getting the null exception (unless you access anything via #this).
So here's how you would use this:
var ds1 = (null as DataSet).Create(); // as oppose to DataSet.Create()
// or
DataSet ds2 = null;
ds2 = ds2.Create();
// using some of the techniques above you could have this:
(null as Console).WriteBlueLine(...); // as oppose to Console.WriteBlueLine(...)
Now WHY did I pick calling the default constructor as an example, and AND why don't I just return new T() in the first code snippet without doing all of that Expression garbage?
Well todays your lucky day because you get a 2fer. As any advanced .NET developer knows, new T() is slow because it generates a call to System.Activator which uses reflection to get the default constructor before calling it. Damn you Microsoft!
However my code calls the default constructor of the object directly.
Static extensions would be better than this but desperate times call for desperate measures.
It's not possible.
And yes, I think MS made a mistake here.
Their decision does not make sense and forces programmers to write (as described above) a pointless wrapper class.
Here is a good example: Trying to extend static MS Unit testing class Assert: I want 1 more Assert method AreEqual(x1,x2).
The only way to do this is to point to different classes or write a wrapper around 100s of different Assert methods. Why!?
If the decision was being made to allow extensions of instances, I see no logical reason to not allow static extensions. The arguments about sectioning libraries does not stand up once instances can be extended.
I stumbled upon this thread while trying to find an answer to the same question the OP had. I didn't find the answer I wanted, but I ended up doing this.
public static class Helpers
{
public static void WriteLine(this ConsoleColor color, string text)
{
Console.ForegroundColor = color;
Console.WriteLine(text);
Console.ResetColor();
}
}
And I use it like this:
ConsoleColor.Cyan.WriteLine("voilĂ ");
As of C#7 this isn't supported. There are however discussions about integrating something like that in C#8 and proposals worth supporting.
Maybe you could add a static class with your custom namespace and the same class name:
using CLRConsole = System.Console;
namespace ExtensionMethodsDemo
{
public static class Console
{
public static void WriteLine(string value)
{
CLRConsole.WriteLine(value);
}
public static void WriteBlueLine(string value)
{
System.ConsoleColor currentColor = CLRConsole.ForegroundColor;
CLRConsole.ForegroundColor = System.ConsoleColor.Blue;
CLRConsole.WriteLine(value);
CLRConsole.ForegroundColor = currentColor;
}
public static System.ConsoleKeyInfo ReadKey(bool intercept)
{
return CLRConsole.ReadKey(intercept);
}
}
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteBlueLine("This text is blue");
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
}
}
Nope. Extension method definitions require an instance of the type you're extending. It's unfortunate; I'm not sure why it's required...
You can't add static methods to a type. You can only add (pseudo-)instance methods to an instance of a type.
The point of the this modifier is to tell the C# compiler to pass the instance on the left-side of the . as the first parameter of the static/extension method.
In the case of adding static methods to a type, there is no instance to pass for the first parameter.
As for extension methods, extension methods themselves are static; but they are invoked as if they are instance methods. Since a static class is not instantiable, you would never have an instance of the class to invoke an extension method from. For this reason the compiler does not allow extension methods to be defined for static classes.
Mr. Obnoxious wrote: "As any advanced .NET developer knows, new T() is slow because it generates a call to System.Activator which uses reflection to get the default constructor before calling it".
New() is compiled to the IL "newobj" instruction if the type is known at compile time. Newobj takes a constructor for direct invocation. Calls to System.Activator.CreateInstance() compile to the IL "call" instruction to invoke System.Activator.CreateInstance(). New() when used against generic types will result in a call to System.Activator.CreateInstance(). The post by Mr. Obnoxious was unclear on this point... and well, obnoxious.
This code:
System.Collections.ArrayList _al = new System.Collections.ArrayList();
System.Collections.ArrayList _al2 = (System.Collections.ArrayList)System.Activator.CreateInstance(typeof(System.Collections.ArrayList));
produces this IL:
.locals init ([0] class [mscorlib]System.Collections.ArrayList _al,
[1] class [mscorlib]System.Collections.ArrayList _al2)
IL_0001: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
IL_0006: stloc.0
IL_0007: ldtoken [mscorlib]System.Collections.ArrayList
IL_000c: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0011: call object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type)
IL_0016: castclass [mscorlib]System.Collections.ArrayList
IL_001b: stloc.1
I tried to do this with System.Environment back when I was learning extension methods and was not successful. The reason is, as others mention, because extension methods require an instance of the class.
It is not possible to write an extension method, however it is possible to mimic the behaviour you are asking for.
using FooConsole = System.Console;
public static class Console
{
public static void WriteBlueLine(string text)
{
FooConsole.ForegroundColor = ConsoleColor.Blue;
FooConsole.WriteLine(text);
FooConsole.ResetColor();
}
}
This will allow you to call Console.WriteBlueLine(fooText) in other classes. If the other classes want access to the other static functions of Console, they will have to be explicitly referenced through their namespace.
You can always add all of the methods in to the replacement class if you want to have all of them in one place.
So you would have something like
using FooConsole = System.Console;
public static class Console
{
public static void WriteBlueLine(string text)
{
FooConsole.ForegroundColor = ConsoleColor.Blue;
FooConsole.WriteLine(text);
FooConsole.ResetColor();
}
public static void WriteLine(string text)
{
FooConsole.WriteLine(text);
}
...etc.
}
This would provide the kind of behaviour you are looking for.
*Note Console will have to be added through the namespace that you put it in.
The following was rejected as an edit to tvanfosson's answer. I was asked to contribute it as my own answer. I used his suggestion and finished the implementation of a ConfigurationManager wrapper. In principle I simply filled out the ... in tvanfosson's answer.
No. Extension methods require an instance of an object. You can
however, write a static wrapper around the ConfigurationManager
interface. If you implement the wrapper, you don't need an extension
method since you can just add the method directly.
public static class ConfigurationManagerWrapper
{
public static NameValueCollection AppSettings
{
get { return ConfigurationManager.AppSettings; }
}
public static ConnectionStringSettingsCollection ConnectionStrings
{
get { return ConfigurationManager.ConnectionStrings; }
}
public static object GetSection(string sectionName)
{
return ConfigurationManager.GetSection(sectionName);
}
public static Configuration OpenExeConfiguration(string exePath)
{
return ConfigurationManager.OpenExeConfiguration(exePath);
}
public static Configuration OpenMachineConfiguration()
{
return ConfigurationManager.OpenMachineConfiguration();
}
public static Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
{
return ConfigurationManager.OpenMappedExeConfiguration(fileMap, userLevel);
}
public static Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap)
{
return ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
}
public static void RefreshSection(string sectionName)
{
ConfigurationManager.RefreshSection(sectionName);
}
}
yes, in a limited sense.
public class DataSet : System.Data.DataSet
{
public static void SpecialMethod() { }
}
This works but Console doesn't because it's static.
public static class Console
{
public static void WriteLine(String x)
{ System.Console.WriteLine(x); }
public static void WriteBlueLine(String x)
{
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.Write(.x);
}
}
This works because as long as it's not on the same namespace. The problem is that you have to write a proxy static method for every method that System.Console have. It's not necessarily a bad thing as you can add something like this:
public static void WriteLine(String x)
{ System.Console.WriteLine(x.Replace("Fck","****")); }
or
public static void WriteLine(String x)
{
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.WriteLine(x);
}
The way it works is that you hook something into the standard WriteLine. It could be a line count or bad word filter or whatever. Whenever you just specify Console in your namespace say WebProject1 and import the namespace System, WebProject1.Console will be chosen over System.Console as default for those classes in namespace WebProject1. So this code will turn all the Console.WriteLine calls into blue insofar as you never specified System.Console.WriteLine.
You can use a cast on null to make it work.
public static class YoutTypeExtensionExample
{
public static void Example()
{
((YourType)null).ExtensionMethod();
}
}
The extension:
public static class YourTypeExtension
{
public static void ExtensionMethod(this YourType x) { }
}
YourType:
public class YourType { }
Although the methods of Console are static, its static methods Write() and WriteLine() merely redirect the call to Console.Out.Write() and Console.Out.WriteLine() respectively. Out is an instance whose type derives from the abstract class TextWriter. This makes it possible to define extension methods for TextWriter:
public static class ConsoleTextWriterExtensions
{
public static void WriteBlueLine(this TextWriter writer, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
writer.WriteLine(text);
Console.ResetColor();
}
public static void WriteUppercase(this TextWriter writer, string text)
{
writer.Write(text.ToUpper());
}
}
The method can then be invoked like this:
Console.Out.WriteBlueLine();
And the best part is that the type of the standard error stream instance Console.Error also derives from TextWriter which makes the same extension method also usable for Console.Error:
Console.Error.WriteBlueLine();
This can be quite useful if you have defined an extension method like WriteTable()(for writing a table out to the console) because you can also use it for the error stream or any other object of TextWriter.
Newer versions of C# allow this to be even shorter with a using static statement for Console to get red of the Console. prefix:
using static System.Console;
Out.WriteBlueLine("A blue line");
Error.WriteBlueLine("A blue line");
unfotunately NO, you CANNOT extend static classes
https://onecompiler.com/csharp/3xvbe7axg
using System;
namespace HelloWorld
{
public static class console_extensions {
public static void EXTENSION(this object item) {
System.Console.WriteLine("HELLO THERE!");
}
}
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
Console.EXTENSION();
((Console)null).EXTENSION();
Console l = new Console();
l.EXTENSION();
}
}
}
output
Compilation failed: 4 error(s), 0 warnings
HelloWorld.cs(16,12): error CS0117: `System.Console' does not contain a definition for `EXTENSION'
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
HelloWorld.cs(17,5): error CS0716: Cannot convert to static type `System.Console'
HelloWorld.cs(18,4): error CS0723: `l': cannot declare variables of static types
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
HelloWorld.cs(18,16): error CS0712: Cannot create an instance of the static class `System.Console'
/usr/lib/mono/4.5/mscorlib.dll (Location of the symbol related to previous error)
however you CAN pass null to the extension method
using System;
namespace HelloWorld
{
public static class static_extensions {
public static void print(this object item, int data = 0) {
Console.WriteLine("EXT: I AM A STATIC EXTENSION!");
Console.WriteLine("EXT: MY ITEM IS: " + item);
Console.WriteLine("EXT: MY DATA IS: " + data);
string i;
if (item == null) {
i = "null";
} else {
i = item.GetType().Name;
}
Console.WriteLine("EXT: MY TYPE IS: " + i + "\n");
}
}
public class Program
{
public static void Main(string[] args)
{
// an extension method can be
// called directly
// (null is an instance)
static_extensions.print(null);
// an extension method can also be
// called directly with arguments
// (null is an instance)
static_extensions.print(null, 1);
// an extension method can also be
// called as part of an instance
int x = 0; // initialize int
x.print();
// an extension method can also be
// called as part of an instance
// and with data
int x2 = 0; // initialize int
x2.print(2);
// an extension method can also be
// called directly from null
// since `null` is an instance
((string)null).print();
// an extension method can also be
// called directly from null
// and with data
// since `null` is an instance
((string)null).print(4);
}
}
}
live example: https://onecompiler.com/csharp/3xvbc8s6w
output:
EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS:
EXT: MY DATA IS: 0
EXT: MY TYPE IS: null
EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS:
EXT: MY DATA IS: 1
EXT: MY TYPE IS: null
EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 0
EXT: MY DATA IS: 0
EXT: MY TYPE IS: Int32
EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS: 0
EXT: MY DATA IS: 2
EXT: MY TYPE IS: Int32
EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS:
EXT: MY DATA IS: 0
EXT: MY TYPE IS: null
EXT: I AM A STATIC EXTENSION!
EXT: MY ITEM IS:
EXT: MY DATA IS: 4
EXT: MY TYPE IS: null
I don't really get what people think they'd gain from being able to extend static classes...
What exactly would you be sacrificing by simply doing something like this?
public static class MyConsole
{
public static void WriteBlueLine(string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}
//...
MyConsole.WriteBlueLine("I'm so blue...");
Console.WriteLine("...and I'm not.");
It's minimal extra typing effort and as a bonus, it keeps things transparent...
After all, even a regular extension method is just a shorthand for a helper method. It doesn't allow you to do anything to/with a class (instance) that you wouldn't be able to do from a regular method.
You CAN do this if you are willing to "frig" it a little by making a variable of the static class and assigning it to null. However, this method would not be available to static calls on the class, so not sure how much use it would be:
Console myConsole = null;
myConsole.WriteBlueLine("my blue line");
public static class Helpers {
public static void WriteBlueLine(this Console c, string text)
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(text);
Console.ResetColor();
}
}

Categories

Resources