I'm trying to have an overloaded constructor for a class. I think this should be fairly simple, however I can't seem to make it work.
Any ideas?
public SaveFile(string location)
{
// Constructor logic here
//TODO: Implement save event.
this.Save(location);
}
public SaveFile()
{
string location = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\SaveFile.DAT";
SaveFile(location);
}
This doesn't compile correctly, and I can't figure out how to do make it work.
You have the wrong syntax for calling an overloaded constructor from within the default constructor.
To call an overloaded constructor in the same class, use this syntax:
public ClassName(parameters) : this(otherParameters)
{
// logic
}
If you wanted to call a constructor in the base class, then you would use the base keyword instead of this. In your case the code would read:
public SaveFile() : this(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "SaveFile.DAT") {}
public SaveFile(string location)
{
this.Save(location);
}
public SaveFile()
: this(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\SaveFile.DAT")
{
}
However that really should be:
public SaveFile()
: this(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal),"SaveFile.DAT"))
{
}
Try this
public SaveFile(string location)
{
// Constructor logic here
//TODO: Implement save event.
this.Save(location);
}
public SaveFile(): this(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\SaveFile.DAT")
{
}
Related
I'm not sure if this is possible, but I'm essentially looking for a class constructor redirect.
An example of what I'm attempting:
public class Test
{
public Test() : TestFromOther();
//public Test() => TestFromOther();
public TestFromOther() { return 'this' with some stuff done here }
//another case might be => TestFromOther(defaultparam)
}
I'm trying to do this so that even if the base constructor is called, it redirects to my method.
(I don't want to just put a call to TestFromOther() inside the body of the constructor.. I'm specifically looking for the :TestFromOther() or => operator.. I've seen it before but for the life of me cannot remember how it's done)
EDIT: It's mostly for cleanliness and readability, thus having the Logger.GetCurrentClassLogger();
public class Logger {
private string _callerClass;
// obviously this doesn't function, but is the ideal end product
//public Logger() => GetCurrentClassLogger();
// Ideally I want the constructor to be this function and if a user, for
// whatever reason does call the empty constructor, it goes to this func
public Logger GetCurrentClassLogger() {
StackFrame[] sf = new StackTrace().GetFrames();
string callerName = "";
foreach (StackFrame f in sf) {
if (f == sf[0])
continue;
if (f.GetMethod().Name == ".ctor") {
callerName = f.GetMethod().ReflectedType.Name;
break;
}
callerName = f.GetMethod().Name;
break;
}
this._callerClass = callerName;
return this;
}
}
I trimmed this down about as far as I could for use as an example
You can "chain" constructors. it's not a redirection.
public class Test
{
public Test() : this("defaultParam") {}
public Test(string stringParam) { }
}
It will execute Test(string stringParam) first and then Test()
Edit per the comments and the edited question
static method is the way to achieve what you like:
public static Logger GetCurrentClassLogger() {...}
and the instantiation:
var logger = Logger.GetCurrentClassLogger(); // no new key word here
No, this is not possible. C# only allows you to call a base constructor or another constructor of the current class.
BTW the thing TestFromOther is also not a valid syntax, as it it is neither a method nor a constructor. Further, a constructor is not allowed to return anything.
The typical solution here would rather be to use a single constructor (possibly private such that it cannot be accessed from the outside) that does what you want. Or you may use helper methods for the initialization.
Can I call a constructor from same class method in C#?
Example:
class A
{
public A()
{
/* Do Something here */
}
public void methodA()
{
/* Need to call Constructor here */
}
}
The short answer is No :)
You cannot call constructors as simple methods except these special cases:
You create a new object: var x = new ObjType()
You call a constructor from another constructor of the same type:
class ObjType
{
private string _message;
// look at _this_ being called before the constructor body definition
public ObjType() :this("hello")
{}
private ObjType(string message)
{
_message = message;
}
}
You call a base type constructor from a constructor:
class BaseType
{
private string _message;
// NB: should not be private
protected BaseType(string message)
{
_message = message;
}
}
class ObjType : BaseType
{
// look at _base_ being called before the constructor body execution
public ObjType() :base("hello")
{}
}
UPD. Regarding the workaround with an initialization method proposed in another answer - yes, it's probably a good way. But it's a bit tricky because of the object consistency, which is the reason why constructors are even exist. Any object method is expected to receive the object (this) in a consistent (working) state. And you cannot guarantee it calling a method from a constructor. So any person editing that initialization method or calling constructor in future (probably you) could expect having this guarantee which greatly increases the risk of making mistake. The problem is amplified when you deal with inheritance.
Besides provided answer which answers the question, an easy away to fix your problem is to define an initialization method that is called from both the constructor and your method:
class A
{
private init()
{
// do initializations here
}
public A()
{
init();
}
public void methodA()
{
// reinitialize the object
init();
// other stuff may come here
}
}
Shortly put, you cannot call the constructor, but you don't have to :)
I have been trying to create some "cascading" constructors. One calls the other with more information that before. The two I have so far look like this.
public scan() : this(Environment.Local) { }
public scan(Environment env) {
//it then does some stuff constructor-y things
}
I would like to make another one that can call my second constructor by accepting a string that it will then convert into an Environment. Something to this effect:
public scan(string environment) : this(environment.toString()}
but it just doesn't seem to want to work how I am hoping. Is there a way to pass in this string then call my other environment accepting constructor?
Also the change i'm hoping to make is going to more substantial than just a toString() but I used that to illistrate the point.
I would do it this way: Create a static method that handles converting from string to enum. In this static method, check for validity and return local if not.
public class scan
{
public scan(Environment value) { }
public scan() : this(Environment.Local) { }
public scan(string s) : this(ParseEnum(s)) { }
private static Environment ParseEnum(string s)
{
// default to local
Environment value = Environment.Local;
// try parsing the string
Enum.TryParse<Environment>(s, out value);
// if sucessful, the new value will be returned
// if not, Environment.Local will be returned
return value;
}
public enum Environment
{
Local,
NotLocal,
AnotherOne
}
}
ToString won't work because you end up calling the constructor recursively (plus calling ToString on a string doesn't make much sense). It sounds like you want to Parse te string to an Environment value:
public scan(string environment) :
this((Environment)Enum.Parse(typeof(Environment),environment))
{
}
But you run the risk of an exception being thrown due to an invalid string value, which cannot be caught at compile time.
If Environment was a struct or a class, then you could override the casting operator and rewrite your contructor like this:
public scan(string environment) : this((Environment)environment)
It is not allowed to overload operators on Enum types, so you're out of luck here.
No. You cant call constructor inside of other constructor or do something with parameter inside your constructor that is passed to other constructor before other ctor is called. Yes you can call other constructor and pass result of method execution like ctor() : this(MyMethod()) but still it is not the same as calling other constructor from inside of your ctor.
Typically what is used is :
public scan() { // general initialization logic }
public scan(Environment env) : this()
{
//some special logic here that uses parameter env
}
Or something like windows forms InitializeComponent method. Initialization method that contains initialization logic.
I tried to make this function (and others) and put it in a separate class file in my project that's under "/Helpers/UploadFiles.cs"
namespace Artikelhantering.Helpers
{
public class UploadFiles
{
private void EnsureDirectoriesExist(string SKU)
{
// if the directory doesn't exist - create it.
if (!System.IO.Directory.Exists("//servername/wwwroot/prodimg/" + SKU))
{
System.IO.Directory.CreateDirectory("//servername/wwwroot/prodimg/" + SKU);
}
}
}
Then in the controller I added using Artikelhantering.Helpers;, it's also added to the namespace section of the web.config file and also to global.asa.cx.
Then I figured I could call it from an ActionResult in my controller like this
[ChildActionOnly]
public ActionResult _EnumerateFolder(string SKU)
{
// create directory if it does not exist
EnsureDirectoriesExist(SKU);
ViewBag.SKU = SKU;
var folder = Directory.EnumerateFiles("//servername/wwwroot/prodimg/" + SKU);
return View(folder);
}
But all I get is:
Error 2 The name 'EnsureDirectoriesExist' does not exist in the current context
Tried calling it by writing it as UploadFiles.EnsureDirectoriesExist(); but that doesn't work either. How am I supposed to call these methods without having them all in the same file? I would like to organize this better.
The method is private. You can not access private members of other classes.
Also some other problems here:
The method you wrote is an instance method, so you need to have an instance of the class to call the method.
If you want to call it using UploadFiles.EnsureDirectoryExists(), you need to make it a class method (static).
I'm not sure whether you can create a new directory the way you try to do it. If you are trying to create the directory on the same machine that this code is running on, use local file names.
Sample code for 1):
UploadFiles uf = new UploadFiles();
uf.EnsureDirectoryExists();
Sample code for 2):
public class UploadFiles
{
public static void EnsureDirectoriesExist(string SKU)
{
// if the directory doesn't exist - create it.
if (!System.IO.Directory.Exists("//servername/wwwroot/prodimg/" + SKU))
{
System.IO.Directory.CreateDirectory("//servername/wwwroot/prodimg/" + SKU);
}
}
}
I furthermore suggest that you google for a C# tutorial that provides you with information on what classes are and how they can be used.
First, change the access modifier of EnsureDirectoriesExist to public then
try to change your ActionResult _EnumerateFolder method with the code below:
public ActionResult _EnumerateFolder(string SKU)
{
// create directory if it does not exist
new UploadFiles.EnsureDirectoriesExist(SKU);
ViewBag.SKU = SKU;
var folder = Directory.EnumerateFiles("//servername/wwwroot/prodimg/" + SKU);
return View(folder);
}
First thing that is not correct here is a method accessibility levels. In order to invoke method from outside of the class body it should be public.
Also, way that you are invoking this method is also incorrect. To do it in desired way you should make your class static to avoid creating an instance of a class to invoke method.
So:
public static class Helper
{
public static void EnsureDirectoriesExist(string SKU)
{
...
}
}
Mark your class as static then try this:
public static class UploadFiles
{
public void EnsureDirectoriesExist(string SKU)
{
//your code
}
}
Then:
public ActionResult _EnumerateFolder(string SKU)
{
UploadFiles.EnsureDirectoriesExist(SKU);
//your code
}
make your directory method public and static. Then you can call it something like this
Artikelhantering.Helpers::UploadFiles.EnsureDirectoriesExist(SKU);
If you can't change the signature... you can make a public wrapper method and call it the same way. If you cannot make the method static, then you should create first an instance of your class and finally call the new public wrapper method.
I have the following function in c#:
bool Handle<TCommandHandler, TModel>(TModel model) where TCommandHandler : ICommandHandler<TModel> {
// ...
_container.Resolve<TCommandHandler>();
// ...
}
Since TModel is clear from a function parameter I want some way to not specify its type when calling a function. Ideally I want to call it like:
Handle<MyCommandHandler>(model);
Since this is probably impossible, I came up with the following:
HandleTemp<TModel> Handle<TModel>(TModel model) {
return new HandleTemp<TModel>(model);
}
public class HandleTemp<TModel> {
private TModel _model;
public HandleTemp(TModel model) { _model = model;}
public bool With<TCommandHandler>() where TCommandHandler : ICommandHandler<TModel> {
}
}
So I'm now calling it like:
Handle(model).With<MyCommandHandler>();
Are there other possibilities? Did I make something completely wrong with my solution?
No, your analysis and solution look about right. Indeed, generic type inference can work only on an all-or-nothing basis. If there are some generic parameters that can't be inferred, all must be explicitly stated. Personally I'd quite like a way to say "you worry about these parameters, I'll tell you this one", but... that doesn't exist.
The only other option is to add an artificial extra regular parameter to allow it to infer the generic parameter - a bit yucky.
One other option: challenge the assumption that generics are needed here. For example, could it just be a Type instance? Would:
bool Handle<TModel>(TModel model, Type type)...
...
Handle(model, typeof(MyCommandHandler));
work, for example? I can't answer this directly, as I don't know the particulars of your _container.Resolve<TCommandHandler>(); method, as to whether that could be adjusted to take a Type rather than a <T>.
All the C# compiler needs is a demonstration of the type in the arguments, so instead of attempting to place it in the generic arguments (at the usage site) make something that lets you provide an argument that helps the compiler identify that type. To make it less confusing, here is an example:
// Your classes/interfaces.
class Container
{
public static T Resolve<T>()
{
Console.WriteLine("Resolving {0}", typeof(T).FullName);
return default(T);
}
}
interface ICommandHandler<TModel>
{
void DoSomething();
}
// An implemented ICommandHandler.
public class WackyCommandHandler : ICommandHandler<string>
{
public void DoSomething() { }
}
// Used to help the C# compiler identify types.
public static class Identify
{
public static TypeIdentity<TType> TheType<TType>()
{
return null; // You don't actually need an instance.
}
}
public sealed class TypeIdentity<TType>
{
private TypeIdentity() { }
}
// Your method
static bool Handle<TCommandHandler, TModel>(TModel model, TypeIdentity<TCommandHandler> handler)
where TCommandHandler : ICommandHandler<TModel>
{
var item = Container.Resolve<TCommandHandler>();
return true;
}
// And the usage site:
var a = "hello";
Handle(a, Identify.TheType<WackyCommandHandler>());
Console.ReadLine();