Can one place Lambdas or Func's in String Interpolation statements - c#

Consider the following;
public override string ToString()
{
return $"{HouseName}{StreetLine1 + " : "}{StreetLine2}{PostalTown + " : "}:{PostCode + " : "}{Country}";
}
This is nothing more than a simple override of ToString() to give end users in an application a little more meaningful information about an address entity than they would otherwise get were no override provided.
HouseName, StreetLine2 and Country are all allowed null values on the backend database. I am wondering if rather than writing separate methods to determine the value of these and then return either nothing or the value + " : " there is a way to do this via a Lambda or func within the actual string interpolation statement itself.
I am still learning my way around C# and what searching I have done to date seems to indicate that this probably isn't possible even with the magical Elvis operator. However it's equally possible that I've simply misunderstood what I have been reading.
EDIT
Following #Evk's answer I created the following quick console app.
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var adr = new Address { StreetLine1 = "1 Any Road", PostalTown = "Any Town", PostCode = "AB12 3CD" };
Console.WriteLine($"{(adr.HouseName != null ? " : " + adr.HouseName : "")} : {adr.StreetLine1 } : { (adr.StreetLine2 != null ? " : " + adr.StreetLine2 : "")} : {adr.PostalTown} : {adr.PostCode} ");
Console.ReadLine();
}
}
public class Address
{
public string HouseName { get; set; }
public string StreetLine1 { get; set; }
public string StreetLine2 { get; set; }
public string PostalTown { get; set; }
public string PostCode { get; set; }
public string Country { get; set; }
}
}
This produced the following result
: 1 Any Road : : Any Town : AB12 3CD
In reality I was after
1 Any Road : Any Town : AB12 3CD
and as you can see I have not even factored in Country , which had it been set should have produced;
1 Any Road : Any Town : AB12 3CD : Any Country

if rather than writing separate methods to determine the value of
these and then return either nothing or the value + " : " there is a
way to do this within the actual string interpolation statement itself
You can use "?:" operator, just enclose it in "()":
$"{StreetLine1 + (StreetLine2 != null ? " : " + StreetLine2 : "")}";
However if you just need to join bunch of strings together - use String.Join:
String.Join(" : ", new[] {HouseName, StreetLine1, StreetLine2}.Where(c => c != null));

Related

How to recreate this solution using polymorphism and to allow inserting words from console, to replace the selected ones?

The code given below is a simple solution to a problem, i have to do another one using polymorphism, but i am kinda new in this C# thing (almost know nothing), but i need some ideas how to recreate this code, and the code to be able to take strings from input as desired words to be switched with the default ones. Hope someone will help me, because i have absolutely no idea how to do this (i made this code by some miracle, but this task is on another level for me right now).
Thanks for everybody that will help.
Console.WriteLine("BEFORE: " + value);
string modified = value.Replace("cow", "duck").Replace("moo", "quack");
string modified1 = value.Replace("cow", "cat").Replace("moo", "meow");
string modified2 = value.Replace("cow", "dog").Replace("moo", "aw");
string modified3 = value.Replace("cow", "goat").Replace("moo", "mee");
string modified4 = value.Replace("cow", "sheep").Replace("moo", "bee");
Console.WriteLine("AFTER: " + modified);
Console.WriteLine("AFTER: " + modified1);
Console.WriteLine("AFTER: " + modified2);
Console.WriteLine("AFTER: " + modified3);
Console.WriteLine("AFTER: " + modified4);
}
}
In yours sample only animals where used, therefore class Animal is provided.
Also, given context for text is something resembling speech, therefore Talk method.
Matching yours sample all animals from array replace 'speech' of a cow with own.
public class Animal {
protected string Kind, Says;
protected Animal(string kind, string says) { Kind = kind; Says = says;
}
public string Talk(Animal impersonate, string stream) {
return stream.Replace(impersonate.Kind, Kind).Replace(impersonate.Says, Says);
}
}
public class Cow : Animal { public Cow() : base("cow", "moo") { } }
public class Duck : Animal { public Duck() : base("duck", "quack") { } }
public class Cat : Animal { public Cat() : base("cat", "meow") { } }
public class Dog : Animal { public Dog() : base("dog", "aw") { } }
public class Goat : Animal { public Goat() : base("goat", "mee") { } }
public class Sheep : Animal { public Sheep() : base("sheep", "bee") { } }
class Program {
static void Sample2(string value) {
var cow = new Cow();
foreach (var animal in new Animal[] {
new Duck(),
new Cat(),
new Dog(),
new Goat(),
new Sheep()
})
Console.WriteLine("AFTER: " + animal.Talk(cow, value));
}
static void Main(string[] args) {
var value = "cow does something like moo";
Console.WriteLine("BEFORE: " + value);
Sample1(value);
Sample2(value);
Console.ReadLine();
}
static void Sample1(string value) {
string modified = value.Replace("cow", "duck").Replace("moo", "quack");
string modified1 = value.Replace("cow", "cat").Replace("moo", "meow");
string modified2 = value.Replace("cow", "dog").Replace("moo", "aw");
string modified3 = value.Replace("cow", "goat").Replace("moo", "mee");
string modified4 = value.Replace("cow", "sheep").Replace("moo", "bee");
Console.WriteLine("AFTER: " + modified);
Console.WriteLine("AFTER: " + modified1);
Console.WriteLine("AFTER: " + modified2);
Console.WriteLine("AFTER: " + modified3);
Console.WriteLine("AFTER: " + modified4);
}
}
As shown above, this sample will match provided input. Class and Method names can be renamed to be more generic.

How to avoid calling Base class properties while creating derived class objects?

I have a base class ProductDetails which is responsible for parsing the productstring, there is another class SelfManufactured which inherits from the baseclass ProductDetails, there is another class - ThirdPartyProduct , which inherits from the SelfManufactured class and has additional details which are specific to this class, like ThirdPartyName, ThirdPartyAddress.
a) For SelfManufactured product the string should be - prefixed with 0
b) For ThirdPartyProduct product the string should be - prefixed with 1
workflow goes like this:
I create a ThirdPartyProduct object using following code:
private void ThirdParty_Click(object sender, RoutedEventArgs e)
{
ThirdPartyProduct thirdparty = new ThirdPartyProduct ("1000", "200", "PROD1",
"XYZW", "ABCD");
string thirdpartyProductString = thirdparty.ToString();
}
if you check the variable thirdpartyProductString in below code it is : appending 0 and then 1.
It appends 0 and then 1 instead what I would like to have is only "1" getting prefixed.
I guess since SelfManufactured class is also called while creating ThirdParty object, it keeps appending values, I would like to have a way that ToString() does not append values when not needed.
ProductDetails.cs
using System;
namespace product
{
public class ProductDetails
{
private readonly string _productString;
public string ProductString
{
get => ToString();
}
public ProductDetails(string productId, string productName, string productLot)
{
_productString = // somevalue here....
}
public override string MyString()
{
return _productString;
}
}
}
SelfManufactured.cs
public class SelfManufactured : ProductDetails
{
public override string MyString()
{
string str = string.Empty;
str = "additional value of 0" + // append the identifier as '0' with product string
return str;
}
}
ThirdPartyProduct.cs
public class ThirdPartyProduct : SelfManufactured
{
public string ThirdPartyName { get; set; }
public string ThirdPartyAddress { get; set; }
public override string MyString()
{
string str = string.Empty;
// append the identifier as '1' with product string and add additional details with the string.
return str;
}
}
Since you are calling base.ToString() in "ThirdPartyProduct" class, it obviously calls the base class ToString() method and it adds "0" to it and making the final string as "101000200PROD1XYZWABCD"
If you don't want to do that then you can refer "ProductString" property of ProductDetails class directly from ToString() method of ThirdPartyProduct class. See below my changes
ProductDetails.cs - I am returning the private read-only from here.
public string ProductString
{
get { return _productString; }
}
Then the ToString() method of ThirdPartyProduct.cs class made to following changes
public override string ToString()
{
string str = string.Empty;
// append the identifier as '0' with product string and add additional details with the string.
str = (int)ProductType.ThirdParty + ProductString + ThirdPartyName + ThirdPartyAddress;
return str;
}
Made changes at the following line -
str = (int)ProductType.ThirdParty + base.ToString() + ThirdPartyName + ThirdPartyAddress;
to
str = (int)ProductType.ThirdParty + ProductString + ThirdPartyName + ThirdPartyAddress;
Note:- I hope always the ThirdPartyProduct class should not append "0", then above solution should be fine, else you need to think of other approach for the calculations.
You already have a property in class ProductDetails called "TypeOfProduct". So in SelfManufactured.ToString(), instead of hard-coding the product type, use the property's value:
str = (int)TypeOfProduct + base.ToString();
Then, in ThirdPartyProduct, there's no need to use the product type as this is taken care of in the base class. So instead call base.ToString() followed by the class-specific details:
str = base.ToString() + ThirdPartyName + ThirdPartyAddress;

Array.find() provides strange results

I am in middle of writing an assignment for my part time programming course. The issues with my code is the array.find() and results of that search. It should(In my theory) search the array for information and then post them to the user, however what comes out from all of the searches is the same thing: ass2task1.Program+customer Here are only parts of the code becouse out teacher told us we can post question on the internet as long as we don't post our entire codes
struct customer
{
public int customernumber;
public string customersurname;
public string customerforname;
public string customerstreet;
public string customertown;
public DateTime customerdob;
}
static void Main(string[] args)
{
customer[] customerdetails = new customer[99];
int selector = 0;
int selector2 = 0;
string vtemp = "";
string ctemp = "";
int searchnumber;
string searchforename; //variable/ array declaring
string searchsurname;
string searchtown;
DateTime searchdob;
customer resultnumber;
customer resultforename;
customer resultsurname;
customer resulttown;
customer resultdob;
if (selector2 == 2)
{
Console.Clear();
Console.WriteLine("Enter the forename you are looking for: ");
searchforename = (Console.ReadLine());
resultforename = Array.Find(customerdetails, customer => customer.customerforname == searchforename);
Console.Clear();
Console.WriteLine("Enter the surname you are looking for: "); // all of the searches comes out with ass2task1.Program+customer result
searchsurname = (Console.ReadLine());
resultsurname = Array.Find(customerdetails, customer => customer.customersurname == searchsurname);
Console.WriteLine("The forename resuts:" + resultforename);
Console.WriteLine("The surname resuts:" + resultsurname);
Array.Find() will return the object that matches a predicate, if you want the property value, you would need to do something like: resultforename.customerforname or something similar.
If it is not found, then a default value will be returned, so check for nulls etc.
When you convert an object to a string ("The forename resuts:" + resultforename) it calls the objects ToString() method. Define an appropriate ToString() method:
struct customer
{
public int customernumber;
public string customersurname;
public string customerforname;
public string customerstreet;
public string customertown;
public DateTime customerdob;
public override string ToString()
{
return customersurname + ", " + customerforname;
}
}
To (attempt to) expand on Ric and clcto's answers. The reason you're getting the struct name in your
Console.WriteLine("The forename resuts:" + resultforename);
Console.WriteLine("The surname resuts:" + resultsurname);
Your resultforename is of struct customer - by default Console.WriteLine(struct) does not know how to represent a complex object as a string.
As suggested you could do
Console.WriteLine("The forename resuts:" + resultforename.customerforname);
Or provide your own .ToString() method for the struct as clcto pointed out - doing this you're basically telling Console.WriteLine (or any string representation) how to represent a struct of customer as string.
Don't know if this will help, or make it even less clear. But given:
public struct Foo
{
public string Bar { get; set; }
}
public struct FooTwo
{
public string Bar { get; set; }
public override string ToString()
{
return "This is how to represent a Foo2 as string: " + Bar;
}
}
Foo[] foos = new Foo[99];
Foo foundFoo = foos[0]; // This is equivalent to your find statement... setting a foundFoo local variable to a Foo struct
string foundBar = foos[0].Bar; // This is another way to get to what you're trying to accoomplish, setting a string value representation of your found object.
Console.WriteLine(foundFoo); // Doesn't know how to deal with printing out a Foo struct - simply writes [namespace].Foo
Console.WriteLine(foundFoo.Bar); // Outputs Foo.Bar value
Console.WriteLine(foundBar); // Outputs Foo.Bar value
FooTwo foo2 = new FooTwo();
foo2.Bar = "test bar";
Console.WriteLine(foo2); // outputs: "This is how to represent a Foo2 as string: test bar"

AOP Logging with custom arguments

Before every method executes, I want to log all parameters from that method. For that, I would use AOP (Aspect oriented programming) and create a "Loggable" attribute. But... I also would like to know the content of my parameters. For a string-parameter, that's not a problem. But I would like to know a good solution for every occasion, like objects, ints, doubles,...
Is there any other way to solve this other then to overwrite the ToString() method?
(in examples I always came across a string parameter...)
Example:
public class MyType {
public int Id { get; set; }
public string Name { get; set; }
public double Value { get; set; }
}
[Loggable]
public void IDoWhateverIWant(MyType data, int count, string message){
//Whatever I want
}
IDoWhateverIWant(
new MyType(){
Id = 1,
Name = "My test data name",
Value = 1234.56}
, 5
, "Log me, please");
Logmessage (the way these parameters are presented are the same to me, I just want to see them):
22/07/2014 9:30 Incoming message: IDoWhateverIWant with parameters:
- data : Id = 1
Name = "My test data name"
Value = 1234.56
- count: 5
- message: "Log me, please"
A simple option is to use NewtonSoft.Json to serialize each parameter. This simple example:
public void IDoWhateverIWant(MyType data, int count, string message)
{
string logMessage =
ParameterValueMessage(data, "data") + Environment.NewLine +
ParameterValueMessage(count, "count") + Environment.NewLine +
ParameterValueMessage(message, "message");
Debug.Print(logMessage);
}
public static string ParameterValueMessage<T>(T arg, string name)
{
string result = JsonConvert.SerializeObject(arg, Formatting.Indented);
return name + ": " + result;
}
Produces the following:
data: {
"Id": 1,
"Name": "My test data name",
"Value": 1234.56
}
count: 5
message: "Log me, please"
My own preference though is for each method to take a single parameter object - the logging code is a lot neater and more generic with parameter objects and all of the individual parameter names can be inferred from the parameter object:
public class MyParameterObject
{
public MyType data { get; set; }
public int count { get; set; }
public string message { get; set; }
}
which is serialized in much the same way and has the benefit of not having to pass in the name of every individual parameter:
public void IAlsoDoWhateverIWant(MyParameterObject parameterObject)
{
string logMessage = ParameterValueMessage(parameterObject);
Debug.Print(logMessage);
}
public static string ParameterValueMessage<T>(T arg)
{
return JsonConvert.SerializeObject(arg, Formatting.Indented);
}
and produces the following output:
{
"data": {
"Id": 1,
"Name": "My test data name",
"Value": 1234.56
},
"count": 5,
"message": "Log me, please"
}

from derived class to base class

i am trying to create a football simulation program. i have a main class named "team" and 4 derived classes named "goalKeeper", "defender", "forward" and "midfielder".
i am creating players according to their position.
ex:
team fb = new team("fb");
forward alex = new forward(fb.tName, "alex", 73, 77, 77, 69, 70);
my team class:
public class team
{
public string tName;
public team(string tName)
{
this.tName = tName;
}
public string teamInfo()
{
return tName;
}
}
forward class:
class forward:team
{
//özellikler
public string pName;
public string pPosName;
public int finishing;
public int longShots;
public int composure;
public int offTheBall;
public int firstTouch;
public forward(string tName, string pName, int finishing, int longShots, int composure, int offTheBall, int firstTouch)
: base(tName)
{
this.pName = pName;
this.pPosName = "Forward";
this.finishing = finishing;
this.longShots = longShots;
this.composure = composure;
this.offTheBall = offTheBall;
this.firstTouch = firstTouch;
}
//etkiyi hesapla
public double influence
{
get
{
//calculations
return processed;
}
}
//futbolcunun genel bilgileri
public void playerInfo()
{
Console.WriteLine( "\n##############################\n" + pName + "-" + tName + "-" + pPosName + "\n" + "Finishing= " + finishing + "\n" + "Long Shots= " + longShots + "\n" + "Composure= " + composure + "\n" + "Off the ball= " + offTheBall + "\n" + "Frist Touch= " + firstTouch + "\n##############################\n");
}
}
as you can see i am calculating influence of each player according to their technical attributes.
what i want is automating the process. for example i've created a team.. added players, and i want all player's influence to be called via team name. i am going to give team name and position name and it is gonna give me average influence of players in that team's chosen position.
how can i do this?
thanks in advance...
note: my code might look stupid. i am a newbie :)
A forward IS A team?
Not at all... A team HAS A forward...
Dont use inheritance... use composition instead.
A player is not a team, this would give you an idea
public class Team
{
private IList<Player> _players
...
}
public class Player
{
public string Name {get;set;}
public abstract Influence { get; }
}
public class Forward : Player
{
public override Influence
{
get { return //calculation }
}
}
I would suggest rethinking your inheritence strategy.
When a class inherits another this implies that the child class 'is a' base class. Applying this to your model implies that a forward 'is a' team which doesn't make much sense. In reality a team 'has a' forward(s).
A more accurate model for what you are trying to achieve is to have a player class as your base class that your foward class, defender class etc inherits from. Your team class can then contains a collection of player classes.

Categories

Resources