C
C#ā€¢2y ago
uselessxp

ā” best way to store and handle Settings/Config of an app

I realized a little tool and I'd like to create a Settings/Configuration system for store some info, example I have several
string serverAddress = "127.0.0.1";
string sshUser = "admin2";
string sshPassword = "password123";
bool isSFTP = true;
...
...
...
string serverAddress = "127.0.0.1";
string sshUser = "admin2";
string sshPassword = "password123";
bool isSFTP = true;
...
...
...
and I'd like to put them in a .ini or whatever file, so I can edit them without having to edit the source code I found few packages I think could works for the purpose: Serilog.Settings.Configuration 215.4M downloads Microsoft.Extensions.Configuration.Ini 47.6M downloads I don't know if they are good and if there exist better stuffs
105 Replies
Pobiega
Pobiegaā€¢2y ago
serilog is a logging library, so thats not really relevant here. M.E.C is however a configuration library that does pretty much exactly what you want
jcotton42
jcotton42ā€¢2y ago
how are these settings intended to be updated? just by updating a file? with some sort of UI? M.E.C does not work well for the latter
uselessxp
uselessxpā€¢2y ago
in this case I expect to open this file with notepad and edit it, just for avoid to having to change the source and recompile everytime I thought something like this (crystaldisk sample)
[Setting]
DebugMode="0"
AutoRefresh="10"
StartupWaitTime="30"
Temperature="0"
ResidentMinimize="0"
MegaRAID="1"
StartupFixed="1"
Language="English"
X="508"
Y="138"
[Workaround]
ExecFailed="0"
[USB]
SAT="1"
IODATA="1"
Sunplus="1"
Logitec="1"
Prolific="1"
JMicron="1"
Cypress="1"
ASM1352R="1"
UsbMemory="0"
NVMeJMicron="1"
NVMeASMedia="1"
NVMeRealtek="1"
[Setting]
DebugMode="0"
AutoRefresh="10"
StartupWaitTime="30"
Temperature="0"
ResidentMinimize="0"
MegaRAID="1"
StartupFixed="1"
Language="English"
X="508"
Y="138"
[Workaround]
ExecFailed="0"
[USB]
SAT="1"
IODATA="1"
Sunplus="1"
Logitec="1"
Prolific="1"
JMicron="1"
Cypress="1"
ASM1352R="1"
UsbMemory="0"
NVMeJMicron="1"
NVMeASMedia="1"
NVMeRealtek="1"
but this morning I read on the web about appsettings.json it seems like something already exist so in this case I'd just have to implement it, in web apps it's autogenerated, but not in consoleapps oh, I think we're talking about the same thing Microsoft.Extensions.Configuration.Json
Pobiega
Pobiegaā€¢2y ago
good news, appsettings.json in ASP.NET uses M.E.C šŸ™‚ yes its very easy to get it going in console apps too
uselessxp
uselessxpā€¢2y ago
not I install it and I try
Pobiega
Pobiegaā€¢2y ago
Microsoft.Extensions.Configuration.Ini exists btw
uselessxp
uselessxpā€¢2y ago
oh, very nice https://www.nuget.org/packages?q=Microsoft.Extensions.Configuration&frameworks=&tfms=&packagetype=&prerel=true&sortby=relevance I'm checking there, what does the first pack do? it's called just Microsoft.Extensions.Configuration
Pobiega
Pobiegaā€¢2y ago
thats the base functionality you will need that the .ini one just adds support for reading ini files
uselessxp
uselessxpā€¢2y ago
so if I install Microsoft.Extensions.Configuration.Json it will install also Microsoft.Extensions.Configuration
Pobiega
Pobiegaā€¢2y ago
yes
uselessxp
uselessxpā€¢2y ago
ok just installed
uselessxp
uselessxpā€¢2y ago
I don't see the base one, should I install it manually?
uselessxp
uselessxpā€¢2y ago
<ItemGroup>
<PackageReference Include="FluentFTP" Version="44.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="SSH.NET" Version="2020.0.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP" Version="44.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="SSH.NET" Version="2020.0.2" />
</ItemGroup>
Pobiega
Pobiegaā€¢2y ago
no, you dont need to explicitly add the base one unless you need to pin its version (which you probably dont want to do)
uselessxp
uselessxpā€¢2y ago
ok
uselessxp
uselessxpā€¢2y ago
I now created an appsettings.json is it normal I see this and I can just clean it or there's an existing model I can add?
uselessxp
uselessxpā€¢2y ago
maybe this one? .settings
Pobiega
Pobiegaā€¢2y ago
uhm you dont write C# code in a json file :p
{
}
{
}
thats a "blank" settings file in json
uselessxp
uselessxpā€¢2y ago
ok
uselessxp
uselessxpā€¢2y ago
I just found this on google, maybe it's a predefined model, there is Json and Json Schema
Pobiega
Pobiegaā€¢2y ago
there is no predefined model and you dont want a scehma file those are something different
uselessxp
uselessxpā€¢2y ago
ok perfect, I created an empty json and setted it as "Copy to Output Directory"
Pobiega
Pobiegaā€¢2y ago
good šŸ™‚
uselessxp
uselessxpā€¢2y ago
var builder = new ConfigurationBuilder();
builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

IConfiguration config = builder.Build();
string connectionString = config["ConnectionString:SqlServer"];
Console.WriteLine(connectionString);
var builder = new ConfigurationBuilder();
builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

IConfiguration config = builder.Build();
string connectionString = config["ConnectionString:SqlServer"];
Console.WriteLine(connectionString);
I followed this sample with sample data and it seems to works about this:
string connectionString = config["ConnectionString:SqlServer"];
string connectionString = config["ConnectionString:SqlServer"];
are there better forms? I noticed I have to pass this "ConnectionString:SqlServer" as a string, I mean, the compiler don't give me hints about existings parameters in appsettings.json, example, if I type Conn it does not autocomplete
Pobiega
Pobiegaā€¢2y ago
correct thats the most basic form of doing it M.E.C contains a few optional ways of binding your configuration to an object
uselessxp
uselessxpā€¢2y ago
string connectionString = config.GetSection("ConnectionString").GetSection("SqlServer").Value;
string connectionString = config.GetSection("ConnectionString").GetSection("SqlServer").Value;
found this also, but I think the first one is prettier
Pobiega
Pobiegaā€¢2y ago
Microsoft.Extensions.Configuration.Binder
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();

// Get values from the config given their key and their target type.
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();

// Write the values to the console.
Console.WriteLine($"KeyOne = {settings.KeyOne}");
Console.WriteLine($"KeyTwo = {settings.KeyTwo}");
Console.WriteLine($"KeyThree:Message = {settings.KeyThree.Message}");
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();

// Get values from the config given their key and their target type.
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();

// Write the values to the console.
Console.WriteLine($"KeyOne = {settings.KeyOne}");
Console.WriteLine($"KeyTwo = {settings.KeyTwo}");
Console.WriteLine($"KeyThree:Message = {settings.KeyThree.Message}");
to use this, you make a class that has the same structure as your settings and then you can access it like so
uselessxp
uselessxpā€¢2y ago
oh cool, in this way I don't have to remember exact parameter names
uselessxp
uselessxpā€¢2y ago
is EnvironmentVariables necessary too? I'm liking this very much, I made some Angular tasks many days ago but I literally lost my head for very easy stuffs, and ppl say Angular is easier than C#
Pobiega
Pobiegaā€¢2y ago
if you want to access environment variables as part of your configuration, yes. if not, no
uselessxp
uselessxpā€¢2y ago
ok can I store bool values? I removed " quotes around true obviously in the json file, like this
"isSFTP": true
"isSFTP": true
but when I type
bool isSFTP = config["myapp:isSFTP"];
bool isSFTP = config["myapp:isSFTP"];
it says cannot convert string to bool, but I removed quotes šŸ§
Pobiega
Pobiegaā€¢2y ago
yes well, you can't access it via that way but you can via the binding
uselessxp
uselessxpā€¢2y ago
oh ok :/ the next thing I want to do is to integrate a logging library like this or the microsoft one, I guess is Microsoft.Extensions.Logging I never used a logging library, also in this case, as a consoleapp, I putted many Console.WriteLine(""); for type what's happening and what I'm doing, additionally I can just save those prints in a .log file generated like me does Serilog make the same thing or what?
Pobiega
Pobiegaā€¢2y ago
Serilog is the king of logging frameworks if you want, you can develop with M.E.L and add the serilog adapter that "combines" them, but imho just go for serilog directly serilog works around structured logging events and multiple "sinks" so you can have a file sink that writes logs to file, and ALSO have a console sink that prints to the console and later add in a SEQ sink, or ELK, or whatever log aggregator you like
uselessxp
uselessxpā€¢2y ago
M.E.L. have more downloads but anyway as I never used them idk which is better
Pobiega
Pobiegaā€¢2y ago
serilog
uselessxp
uselessxpā€¢2y ago
ok
Pobiega
Pobiegaā€¢2y ago
MEL is used by all official MS stuff, thats why it has so many downloads and its not bad, just doesnt have nearly as much features as serilog
uselessxp
uselessxpā€¢2y ago
I'm reading some samples but I don't fully understand what does this serilog do, this is a sample from their official website
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;
log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);
var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;
log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);
isn't just almost the same thing that I do with Console.WriteLine? yeah it add date and hour before, and colors, but as I'm understanding I have to manually write what to print
Pobiega
Pobiegaā€¢2y ago
yes, of course if you didnt tell it what to write, how would it know? šŸ˜› the benefit of this is that one, that data is structured. its not just a string
uselessxp
uselessxpā€¢2y ago
couldn't I achieve the same by adding something like DataTime.Now at the beginning?
Pobiega
Pobiegaā€¢2y ago
and also that you can easily configure this to store the data in a file AND print it to the console uh.. no? that would just add time info to the string you are only writing to a console
public class SerilogProgram
{
public static void Run()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Minute)
.CreateLogger();

Log.Information("Hello, world!");

int a = 10, b = 0;
try
{
Log.Debug("Dividing {A} by {B}", a, b);
Console.WriteLine(a / b);
}
catch (Exception ex)
{
Log.Error(ex, "Something went wrong");
}
finally
{
Log.CloseAndFlush();
}
}
}
public class SerilogProgram
{
public static void Run()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Minute)
.CreateLogger();

Log.Information("Hello, world!");

int a = 10, b = 0;
try
{
Log.Debug("Dividing {A} by {B}", a, b);
Console.WriteLine(a / b);
}
catch (Exception ex)
{
Log.Error(ex, "Something went wrong");
}
finally
{
Log.CloseAndFlush();
}
}
}
here is a serilog demo I had lying around this will log to a file and print to the console, all configured in a single location. It will add log level and timestamp information.
uselessxp
uselessxpā€¢2y ago
so benefits are: - log level (debug, information, warning... etc) - time - automatic log to file
Pobiega
Pobiegaā€¢2y ago
its way more than that, but thats some of it
uselessxp
uselessxpā€¢2y ago
well it seems nice, so all I should to after installing it is to replace all Console.WriteLine with log.
Pobiega
Pobiegaā€¢2y ago
its easy to use, and configured in one place only. that means you dont need to update every place you call your log function if you decide to change how you do things yep, thats the first step
uselessxp
uselessxpā€¢2y ago
well why don't do it^^ not I try
uselessxp
uselessxpā€¢2y ago
I never understood a thing, if I install the first one am I including all others?
uselessxp
uselessxpā€¢2y ago
I guess I need the third instead Serilog.Extensions.Logging a sample I found online only use those 2:
using Serilog;
using Serilog.Sinks;
using Serilog;
using Serilog.Sinks;
Pobiega
Pobiegaā€¢2y ago
no, the first one is the base it wont include any other but Serilog.Sinks.File will include base serilog you need the sinks you want, most likely File and Console
uselessxp
uselessxpā€¢2y ago
ok, so Sinks.File is for log to a file
Pobiega
Pobiegaā€¢2y ago
yup
uselessxp
uselessxpā€¢2y ago
if the console logging is included in the base why they created Serilog.Extensions.Logging ?
Pobiega
Pobiegaā€¢2y ago
its not included in the base S.E.L is the adapter library that makes it work with M.E.L
uselessxp
uselessxpā€¢2y ago
ohh ok I think a similar thing
Pobiega
Pobiegaā€¢2y ago
you could read the description on the packages
uselessxp
uselessxpā€¢2y ago
Serilog.Settings.Configuration Microsoft.Extensions.Configuration (appsettings.json) support for Serilog yesterday I thought it was something like M.E.C realized by Serilog author
uselessxp
uselessxpā€¢2y ago
so I guess I need those 2
Pobiega
Pobiegaā€¢2y ago
yup.
uselessxp
uselessxpā€¢2y ago
I assume this is an old sample, this made both by only including .Sinks (or maybe he installed both and included all .Sinks "sublevels"
Pobiega
Pobiegaā€¢2y ago
packages and namespaces are not 1-1 correlated so Serilog.Sinks.Console doesnt actually need a using Serilog.Sinks.Console; at the top to work it adds an extension method on the Log.WriteTo object
uselessxp
uselessxpā€¢2y ago
so you are telling me that this:
using System.Buffers.Binary;
using System.Buffers.Text;
using System.Buffers.Binary;
using System.Buffers.Text;
is the same of:
using System.Buffers;
using System.Buffers;
Pobiega
Pobiegaā€¢2y ago
no Im not
uselessxp
uselessxpā€¢2y ago
oh ok now I und
Pobiega
Pobiegaā€¢2y ago
Im saying that a package name has no impact on the namespaces it can declare objects in
uselessxp
uselessxpā€¢2y ago
so it's plausible that this dude had Serilog.Sinks.Console installed but he didn't added the namespace since it's not supposed to be added
Pobiega
Pobiegaā€¢2y ago
correct.
using Serilog;

namespace TestingConsoleApp.SerilogTest;

public class SerilogProgram
{
public static void Run()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Minute)
.CreateLogger();

Log.Information("Hello, world!");

int a = 10, b = 0;
try
{
Log.Debug("Dividing {A} by {B}", a, b);
Console.WriteLine(a / b);
}
catch (Exception ex)
{
Log.Error(ex, "Something went wrong");
}
finally
{
Log.CloseAndFlush();
}
}
}
using Serilog;

namespace TestingConsoleApp.SerilogTest;

public class SerilogProgram
{
public static void Run()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Minute)
.CreateLogger();

Log.Information("Hello, world!");

int a = 10, b = 0;
try
{
Log.Debug("Dividing {A} by {B}", a, b);
Console.WriteLine(a / b);
}
catch (Exception ex)
{
Log.Error(ex, "Something went wrong");
}
finally
{
Log.CloseAndFlush();
}
}
}
thats the full code from this file it uses both Sinks.File and Sinks.Console, as you can see
uselessxp
uselessxpā€¢2y ago
I'm twisted now :/ like when you find out Santa does not exists
Pobiega
Pobiegaā€¢2y ago
well you clearly had an incorrect understanding of what namespaces are and how they work :p
uselessxp
uselessxpā€¢2y ago
all I knew about namespaces is that they're just an alias definer or an object and they need to be included with using in order to use its objects or part of them till now I always used this approach when didn't know which pack install writing this
Console.WriteLine("Something . . .");
log.Information("Something . . .");
Console.WriteLine("Something . . .");
log.Information("Something . . .");
so VisualStudio tell me which pack install for correct the error šŸ¦Š
Pobiega
Pobiegaā€¢2y ago
no VS wont tell you what to install, it will tell you what references you need but that only works for things already in the solution, or BCL classes iirc it wont recommend third-party nugets
uselessxp
uselessxpā€¢2y ago
ok ok just tried it on my skin šŸ¤£ it recommend me to install only Serilog it solve the error red line under log. but it doesn't print stuffs since I had to install Sinks.Console and instantiate it with LoggerConfiguration() it works like a charm
using var log = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/myapp.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
using var log = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/myapp.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
which name could be elegant for a .log file? could using myapp.log be pretty?
Pobiega
Pobiegaā€¢2y ago
you shouldn't have a using on that or well, you might be able to get away with it, depends on where that code is but in general, dont - its just disposing the logger
uselessxp
uselessxpā€¢2y ago
ok
uselessxp
uselessxpā€¢2y ago
obs studio log files just use the dates without putting a prefix
uselessxp
uselessxpā€¢2y ago
log.Information("message 1");
log.Information("message 2");
log.Information("\nmessage 3");
log.Information("message 1");
log.Information("message 2");
log.Information("\nmessage 3");
just one thing, but I think it could not be solved with 1 row, looks like I can't space messages like I used to do with cw should I add 1 blank cw row for create a space?
Pobiega
Pobiegaā€¢2y ago
you shouldn't these are log messages, you shouldn't care about how they look in the console adding a blank line like that will make that individual log message weird
uselessxp
uselessxpā€¢2y ago
I'd like to add a blank line for a better view, cause my tool run many cmd commands, that generated their-self many many rows, and I want to separate those generated blocks from the next log message I suppose that if I want to use this library for log all eventual errors I'd have to spam try-catch statements everywhere
Pobiega
Pobiegaā€¢2y ago
probably yes. you usually also set a catch-all try/catch at the top level, to log any fatal crashes that reach that point but it should ideally never trigger but you misunderstand the purpose of a logger if you are worrying about how the output looks
uselessxp
uselessxpā€¢2y ago
at the top level? oh you mean to put the whole code into an unique try catch
Pobiega
Pobiegaā€¢2y ago
yeah, more or less.
uselessxp
uselessxpā€¢2y ago
ok many time ago, when I discovered try-catch statement, I started to spam it every where, like 10-20 times at once for being able to print every possible error, but after a while I read that it's not a good thing to do since I should predict and handle possible errors https://coderr.io/exception-handling Best practice number 1: do not catch exceptions. Let's start by defining what "handled" means when talking about exceptions.
Pobiega
Pobiegaā€¢2y ago
yep or rather best practice number 1: write code so that it doesnt throw exceptions for most cases exceptions should be exceptional if you try to delete a file and get a FileNotFoundException, you as a developer fucked up you should have checked that the file existed before trying to delete it or maybe there is a TryDeleteFile method that doesnt throw, if you dont care
uselessxp
uselessxpā€¢2y ago
yeah about this I found a sample online that do this
if (!dir.Exists)
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
if (!dir.Exists)
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
but which is the sense to throw an exception? the program will crash anyway
Pobiega
Pobiegaā€¢2y ago
generally you throw an exception when you cant handle it locally perhaps you cant show the user an error here, because this is a library and you dont know if the user is an actual human using a GUI or this is a webserver so you throw and let the caller handle it
uselessxp
uselessxpā€¢2y ago
hm, I'll elaborate better this concept in the future, seems abstract for now
uselessxp
uselessxpā€¢2y ago
I'm just assuming that the logger can't be used into other functions that I call from Main() I could replicate this block of code into other functions but I think this will going to generate another file many years ago when I was using VB.NET I used to solve those kind of problems by putting those declarations out of all, immediately after class opening, but this can't be done here xD
Pobiega
Pobiegaā€¢2y ago
it can. usually, you would access it via dependecy injection but serilog also offers a static logger so instead of using var log... write Log.Logger = and you can now globally access that via Log.
uselessxp
uselessxpā€¢2y ago
oh, now I und why people put Serilog inizialitation into another .cs or into another project of the solution the code is cleaner and they can call it from everywhere which solution is better? I guess the DI one
Pobiega
Pobiegaā€¢2y ago
I prefer DI, since it lets me mock the logger for tests
uselessxp
uselessxpā€¢2y ago
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(cb)
.CreateLogger();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(cb)
.CreateLogger();
in this sample I found theres also a .ReadFrom.Configuration(cb) but it's not explained what does it do and only there are no other file available to read but I guess the content is log level, if writetofile, if writetoconsole etc mock the logger? unfortunately I don't understand DI yet, but on the web people say is easy to use and used by tons of coders as utility stuff from what I see this DI seems simple, typing few lines of code should be enough but I feel that I'd do it mechanically, which are requirements in terms of knowledge for understand DI? knowing interfaces?
Pobiega
Pobiegaā€¢2y ago
yes and no interfaces are extremely common, but not actually part of DI itself If you just want a quick idea of what it is and how it works, I recommend this video (that I made) on the topic: https://www.youtube.com/watch?v=USBoZtGt0QU
uselessxp
uselessxpā€¢2y ago
I solved in this way (there are more ways to convert to bool, I used this one)
bool isSFTP = Convert.ToBoolean(config["myapp:isSFTP"]);
bool isSFTP = Convert.ToBoolean(config["myapp:isSFTP"]);
Pobiega
Pobiegaā€¢2y ago
I would suggest you learn to use the model binding approach
public class ConfigModelsProgram
{
public static void Run()
{
var configRoot = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

var testSectionConfig = configRoot.GetSection("MyTestSection").Get<TestSectionConfig>();

Console.WriteLine($"{testSectionConfig.Name}: {testSectionConfig.Number}");
}
}

public class TestSectionConfig
{
public string Name { get; set; }
public int Number { get; set; }
}
public class ConfigModelsProgram
{
public static void Run()
{
var configRoot = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

var testSectionConfig = configRoot.GetSection("MyTestSection").Get<TestSectionConfig>();

Console.WriteLine($"{testSectionConfig.Name}: {testSectionConfig.Number}");
}
}

public class TestSectionConfig
{
public string Name { get; set; }
public int Number { get; set; }
}
uselessxp
uselessxpā€¢2y ago
yeah I'll try to use binding anyway like I prefer that the compiler suggest me variables
Pobiega
Pobiegaā€¢2y ago
you will need Microsoft.Extensions.Configuration.Binder installed
uselessxp
uselessxpā€¢2y ago
ok I make some improvements to the code then I'll make this one also as sort of improvement. Next steps will be to learn Interfaces, since I assumed they're very common, and I can't continue ignore them, and after maybe try to understand DI if not early
Pobiega
Pobiegaā€¢2y ago
interfaces are fairly simple its a contract that a class MUST adhere to if they want to "implement" that interface
uselessxp
uselessxpā€¢2y ago
I seen an YT video about interfaces, and it explained Interfaced are a sort of Inheritance (concept that I mastered theoretically but never practised)
Pobiega
Pobiegaā€¢2y ago
thus you can safely use the methods from the interface without knowing the concrete type eh, it uses the same syntax as inheritance but Im not sure if it actually is inheritance under the surface
uselessxp
uselessxpā€¢2y ago
the guys of the YT tutorial made a similitude like: Inheritance: a child take parents eyes Interface: a child learn the parent job
Pobiega
Pobiegaā€¢2y ago
Pobiega
Pobiegaā€¢2y ago
public interface IStringToIntConverter
{
public int FromString(string input);
}

public class IntParseConverter : IStringToIntConverter
{
public int FromString(string input) => int.Parse(input);
}

public class ConvertToIntConverter : IStringToIntConverter
{
public int FromString(string input) => Convert.ToInt32(input);
}
public interface IStringToIntConverter
{
public int FromString(string input);
}

public class IntParseConverter : IStringToIntConverter
{
public int FromString(string input) => int.Parse(input);
}

public class ConvertToIntConverter : IStringToIntConverter
{
public int FromString(string input) => Convert.ToInt32(input);
}
var converters = new List<IStringToIntConverter>()
{
new IntParseConverter(),
new ConvertToIntConverter()
};

foreach (var converter in converters)
{
Console.WriteLine(converter.FromString("123"));
}
var converters = new List<IStringToIntConverter>()
{
new IntParseConverter(),
new ConvertToIntConverter()
};

foreach (var converter in converters)
{
Console.WriteLine(converter.FromString("123"));
}
converter here is of type IStringToIntConverter meaning we can only access the methods that interface describes
Accord
Accordā€¢2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.