constant string Alternative working with helper classes - c#

When working with switch case, for example
I could use
const string FirstFloor = "lvl1", SecondFloor = "lvl2", ThirdFloor = "lvl3";
string ElavaetTo= "lvl1";
switch(ElavaetTo)
{
case FirstFloor:
Response.Redirect(FirstFloor + "Page.aspx")
break;
case SecondFloor:
Response.Redirect(SecondFloor + "Page.aspx")
break;
case ThirdFloor:
Response.Redirect(ThirdFloor + "Page.aspx")
break;
}
Edited :
this is only an example of where constant string wil not work if placed in another class
this is not a function / method i am trying to correct so it will work.
thanks for your time, i am trying to base my methods , my approach...
This would work fine placed in the current or same class of the project but when all variables are stored outside this class instead of simply instantiating the class and methods only once :
fullClassName shrtNm = New fullClassName();
then you would like to call it as with
shrtNm.MethodName();
You need to go the 'Long way around' specially if not including the Namespace via using statement
and you would have to call it like:
string strnm = MyNameOfNameSpace.fullClassName.ConstantntStrName;
instead of:
string strnm = shrtNm.ConstantStrName;
Is there an alternative to using any type that will represent string values inside the IntelliSense in an easy way ?
I have tried to use
public enum Elavation
{
lvl1,
lvl2,
lvl3
}
but then you need to declare it as in the long example plus a .ToString()
Is there any alternative at all?

Instead of declaring the variables as 'const' have your tired declaring them as 'readonly' ?
This would enable you to simply instantiat the class only once :
fullClassName shrtNm = New FullClassName();
then you would like to call it as with
shrtNm.<VariableName>;
Guessing from the use case you enumerated, I doubt the difference between using const and readonly should matter...

as far as i could get (only because it was important for me to addapt an aproach )
i found an example in a codeProjec page about using strings and String-Enumerations
that lead me to use that aproach and then turn my calss into a static class
public static class Qs
{
public sealed class Act
{
//private Act();
public const string edit = "edit", add = "add", remove = "remove", replace = "replace";
}
public sealed class State
{
public const string addnewTableRow = "addnewTableRow", cancelInsert = "cancelInsert", loadpagefromlink="loadpagefromlink";
}
public sealed class Params
{
public const string state = "state";
public const string custID = "custID";
public const string recordID = "recordID";
}
}
using sealed class accessing it via its parent className.Itsname
e.g.
Qs.Act.edit
as edit would show in IntelliSense

Related

How can I add a default constructor and have it call another constructor and use the default values?

I have this code:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
When I try and use it then it's telling me I am missing a default constructor. How can I add one of these and still make the code use the default values for iconBackgroundColor and IconSource? I thought that adding in those defaults with the = Const. would make it work but it seems like it doesn't think my constructor is a default (with no params).
You just have to add another empty overload and call the required constructor with defaults. See below:
public class NewFrame
{
public NewFrame() : this(Const.Car, Const.Red){
}
public NewFrame(string iconSource,
string iconColor)
{
...
}
}
By having two optional parameters, you don't actually create 4 different constructor declarations under the hood (one with both parameters, one with the first parameter, one with the second parameter, and one with neither). There is still only one constructor, with two parameters. It's just that C# recognises that the parameters are optional, and has syntactic sugar to let you omit them when you call the constructor.
However, if you use reflection to create an instance of your class (probably whatever the thing that requires a default constructor is doing), and you attempt to invoke the parameterless constructor, it won't find one, because there is no syntactic sugar in reflection.
Here is an example:
class MainClass
{
public static void Main(string[] args)
{
Type t = typeof(MainClass);
object o = Activator.CreateInstance(t, 1);
Console.WriteLine(o);
}
public MainClass(int a = 10)
{
}
}
If you use typeof(MainClass).GetConstructors(), it will tell you that there is only one.
To actually declare a default constructor, you can do:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
...
}
public NewFrame() : this(Const.Car, Const.Red) { }
}
For what it's worth, when I do something like this, I take the route that #VyacheslavBenedichuk's answer is showing.
I'm not sure what your complaint is. This code compiles for me:
public class TestConstructor
{
public TestConstructor(string what = Const.Car, string color = Const.Red)
{
}
public static void Test()
{
var tc = new TestConstructor();
}
public class Const
{
public const string Car = "car";
public const string Red = "red";
}
}
What do your definitions of Const.Car and Const.Red look like? Where are you seeing the error?
But, if you use something that requires a default constructor, then this will not work. For example, this will fail at runtime:
var tc2 = Activator.CreateInstance(typeof(TestConstructor));
Please, when you are reporting an error, describe it exactly - in particular say whether it's a runtime or a compile-time error, the exact wording of the error, and the context in which the error occurs. In this case (the call to CreateInstance) will result in a System.MissingMethodException: 'No parameterless constructor defined for this object.'
In this case, you need to follow #VyacheslavBenedichuk's advice

Const string referencing another const string - how to avoid DRY without readonly

public static class Abc
{
public const string Placeholder = "{$content}";
public const string Pattern = $"<div class=\"embed-responsive\">{Placeholder}</div>";
}
How to correctly solve this to avoid breaching DRY (Dont repeat yourself)? I know I can use static readonly, but then it is a bit of a different thing (even though it works..). I think there should be better way? Or is there really not?
While you cannot call a method to initialize a constant value, it is allowed to use operators. If you need to create a constant that contains another constant value, use the plus operator to concatenate string values.
public static class Abc
{
public const string Placeholder = "{$content}";
public const string Pattern = "<div class=\"embed-responsive\">" + Placeholder + "</div>";
}

Call 3rd-party assembly's overloaded method from generic method using dynamic (or by other means)?

Update: Turns out there were details I had completely missed until I looked at the source code of the library I was using. Apologies for the bad example code starting out, was trying to focus on what I thought was relevant.
Working with FlatFiles NuGet library which has 25 overloads for a Property(...) method. I'm trying to dispatch the correct Property(...) overload from my generic method by using dynamic on a parameter I'm passing, but this isn't working. Here's what I tried:
using FlatFiles;
using FlatFiles.TypeMapping;
public class FixedWidthDataSource<FixedWidthRecordT> {
public IFixedLengthTypeMapper<FixedWidthRecordT> Mapper
= FixedLengthTypeMapper.Define<FixedWidthRecordT>()
;
...
public void MapProperty<T>(
Expression<Func<FixedWidthRecordT, T>> col
, int width
, string inputFormat = null
) {
var window = new Window(width);
Mapper.Property((dynamic)col, window);
}
}
public class FixedWidthRecord
{
public string First { get; set; }
public string Last { get; set; }
}
//later
var fwds = new FixedWidthDataSource<FixedWidthRecord>();
fwds.MapProperty(c=>c.First, 5);
A few of the Property overloads:
Property(Expression<Func<FixedWidthRecordT, bool>> property, Window window);
Property(Expression<Func<FixedWidthRecordT, int>> property, Window window);
Property(Expression<Func<FixedWidthRecordT, string>> property, Window window);
The error I get is 'FlatFiles.TypeMapping.IFixedLengthTypeMapper<FixedWidthRecord>' does not contain a definition for 'Property'.
Looking at the source I see the there's an
internal sealed class FixedLengthTypeMapper<TEntity>
and this is the type of object that's being returned from the call to FixedLengthTypeMapper.Define<FixedWidthRecordT>() and assigned to Mapper. However, IFixedLengthTypeMapper does not have any definitions for Property(...), only FixedLengthTypeMapper has them.
Hoping that's all relevant.
Maybe your case has something to do with this? RuntimeBinderException – “does not contain a definition for”.
That article gets that exception in the case of an anonymous object, but your case seems similar. Your assembly is trying to access something through dynamic it cannot normally see: an internal class in your case, an anonymous type in theirs.
Adding the [assembly: InternalsVisibleTo("Your.Assembly")] attribute on the library doesn't sound like a good option, but if you can build from source it could help temporarily. Or maybe with that info you could create a solid repro.
Here is what I finally did to get it working, although it's by using an interface not described in the library's usage documentation. I'm still curious how this could have otherwise been solved (say for instance, if the IFixedLengthTypeConfiguration interface I'm using in the solution were also defined as internal).
using FlatFiles;
using FlatFiles.TypeMapping;
public class FixedWidthDataSource<FixedWidthRecordT> {
public IFixedLengthTypeConfiguration<FixedWidthRecordT> Configuration
= FixedLengthTypeMapper.Define<FixedWidthRecordT>()
;
public IFixedLengthTypeMapper<FixedWidthRecordT> Mapper;
public FixedWidthDataSource() {
Mapper = (IFixedLengthTypeMapper<FixedWidthRecordT>)Configuration;
}
...
public void MapProperty<T>(
Expression<Func<FixedWidthRecordT, T>> col
, int width
, string inputFormat = null
) {
var window = new Window(width);
Configuration.Property((dynamic)col, window);
}
}
public class FixedWidthRecord
{
public string First { get; set; }
public string Last { get; set; }
}
//later
var fwds = new FixedWidthDataSource<FixedWidthRecord>();
fwds.MapProperty(c=>c.First, 5);

How do i access the constant field using instant reference using linq in C#?

I am having a model like below...
public class Class1
{
public const string Example = "Example";
public string Name { get; set:}
}
And one more model named as "Class2" in which "Class1" acts as virtual like below...
public class Class2
{
public int Id{get; set;}
public virtual Class1 class1obj {get; set;}
piblic int class1objId {get; set;}
}
Now I have one service method to get the values hold by model "Class2", mentioned below
GetClass<T>();
now, I planned to get data using below code:
var data = GetClass<Class2>(s => s.class1obj.Example == "Example1");
But, When i type the above code and i tried to access the constant like s.class1obj.Example it throws error and intellisense also shows only the "Name" property and did not shows the const Example declared in "Class1" ? Why, I am not able to access the constant field ? I am in learning process, please can any one help me on this...
You cannot access constants through an instance. You need to use the class name. For example:
var ex = Class1.Example;
An alternative would be to add an access property to your class:
public Class1
{
public const string Example = "Example";
public string ExampleConst { get { return Example; } }
}
Constant fields are implicitly static. This means that they belong not to an instance, but to a type. Therefore, to access the constant field you need to access not a class instance, but a type object, just as you would do with a static field or method. In your case, this means that you access Class1.Example and not class1obj.Example.
Example is a constant, think of it as a property of the class rather than of the object instance.
To access it you'd call
var val = Class1.Example;
and so
var data = GetClass<Class2>(s => Class1.Example == "Example1");
However this doesn't make sense to me (it will ALWAYS return true as it's a constant). I'm not entirely sure what you're trying to do in your lamba so it's difficult to advise any further...

Are Enum the right way to go here?

I'm not sure if I am abusing Enums here. Maybe this is not the best design approach.
I have a enum which declares the possible parameters to method which executes batch files.
public enum BatchFile
{
batch1,
batch2
}
I then have my method:
public void ExecuteBatch(BatchFile batchFile)
{
string batchFileName;
...
switch (batchFile)
{
case BatchFile.batch1:
batchFileName = "Batch1.bat";
break;
case BatchFile.batch2:
batchFileName = "Batch2.bat";
break;
default:
break;
}
...
ExecuteBatchFile(batchFileName);
}
So I was wondering if this is sound design.
Another option I was thinking was creating a Dictionary<> in the constructor like this:
Dictionary<BatchFile, String> batchFileName = new Dictionary<BatchFile, string>();
batchFileName.Add(BatchFile.batch1, "batch1.bat");
batchFileName.Add(BatchFile.batch2, "batch2.bat");
Then instead of using a switch statement I would just go:
public void ExecuteBatch(BatchFile batchFile)
{
ExecuteBatchFile(batchFileName[batchFile]);
}
I'm guessing the latter is the better approach.
I'd probably go for a design along these lines:
public interface IBatchFile
{
void Execute();
}
public class BatchFileType1 : IBatchFile
{
private string _filename;
public BatchFileType1(string filename)
{
_filename = filename;
}
...
public void Execute()
{
...
}
}
public class BatchFileType2 : IBatchFile
{
private string _filename;
public BatchFileType2(string filename)
{
_filename = filename;
}
...
public void Execute()
{
...
}
}
In fact, I'd extract any common functionality into a BatchFile base class
What if you suddenly need a third batch file? You have to modify your code, recompile your library and everybody who uses it, has to do the same.
Whenever I find myself writing magic strings that might change, I consider putting them into an extra configuration file, keeping the data out of the code.
I would personally use a static class of constants in this case:
public static class BatchFiles
{
public const string batch1 = "batch1.bat";
public const string batch2 = "batch2.bat";
}
If you want to use an enum then you may want to consider utilising attributes so you can store additional inforation (such as the file name) against the elements.
Here's some sample code to demonstrate how to declare the attributes:
using System;
public enum BatchFile
{
[BatchFile("Batch1.bat")]
batch1,
[BatchFile("Batch2.bat")]
batch2
}
public class BatchFileAttribute : Attribute
{
public string FileName;
public BatchFileAttribute(string fileName) { FileName = fileName; }
}
public class Test
{
public static string GetFileName(Enum enumConstant)
{
if (enumConstant == null)
return string.Empty;
System.Reflection.FieldInfo fi = enumConstant.GetType().GetField(enumConstant.ToString());
BatchFileAttribute[] aattr = ((BatchFileAttribute[])(fi.GetCustomAttributes(typeof(BatchFileAttribute), false)));
if (aattr.Length > 0)
return aattr[0].FileName;
else
return enumConstant.ToString();
}
}
To get the file name simply call:
string fileName = Test.GetFileName(BatchFile.batch1);
I think the latter approach is better because it separates out concerns. You have a method which is dedicated to associating the enum values with a physical path and a separate method for actually executing the result. The first attempt mixed these two approaches slightly.
However I think that using a switch statement to get the path is also a valid approach. Enums are in many ways meant to be switched upon.
Using enums is ok if you don't need to add new batch files without recompiling / redeploying your application... however I think most flexible approach is to define a list of key / filename pairs in your config.
To add a new batch file you just add it to the config file / restart / tell your user the key. You just need to handle unknown key / file not found exceptions.
Is it really necessary that ExecuteBatch works on limited number of possible file names only?
Why don't you just make it
public void ExecuteBatch(string batchFile)
{
ExecuteBatchFile(batchFile);
}
The problem with the latter case is if something passed an invalid value that is not inside the dictionary. The default inside the switch statement provides an easy way out.
But...if you're enum is going to have a lot of entries. Dictionary might be a better way to go.
Either way, I'd recommend some way to provide protection of the input value from causing a bad error even in ammoQ's answer.
The second approach is better, because it links the batch file objects (enums) with the strings..
But talking about design, it would not be very good to keep the enum and the dictionary separate; you could consider this as an alternative:
public class BatchFile {
private batchFileName;
private BatchFile(String filename) {
this.batchFileName = filename;
}
public const static BatchFile batch1 = new BatchFile("file1");
public const static BatchFile batch2 = new BatchFile("file2");
public String getFileName() { return batchFileName; }
}
You can choose to keep the constructor private, or make it public.
Cheers,
jrh.
The first solution (the switch) is simple and straight forward, and you really don't have to make it more complicated than that.
An alternative to using an enum could be to use properties that returns instances of a class with the relevant data set. This is quite expandable; if you later on need the Execute method to work differently for some batches, you can just let a property return a subclass with a different implementation and it's still called in the same way.
public class BatchFile {
private string _fileName;
private BatchFile(string fileName) {
_fileName = fileName;
}
public BatchFile Batch1 { get { return new BatchFile("Batch1.bat"); } }
public BatchFile Batch2 { get { return new BatchFile("Batch2.bat"); } }
public virtual void Execute() {
ExecuteBatchFile(_fileName);
}
}
Usage:
BatchFile.Batch1.Execute();

Categories