I want to be able to have a class Named Musician, with a rule/Property called Hits( which is an Array-list, with two methods called ListHits() and AddHits(string)
ListHits returns a string containing all the hits separa
ted by a comma
AddHit – adds a hit to the Hits arrayList. Each hit is
a string between 1 and 50 characters long with no l
eading
or trailing white space.
I have no idea how to go about doing this im familiar with collections and adding values to Lists and i know how to set basic properties
-- i have tried for hours on end please HELP!
public class Musician : Celebrity
{
private string _hits;
public string Hits
{
get { return _hits; }
set
{
if (value.Length < 1)
{
throw new Exception("need more then 2 characters");
}
if (value.Length > 50)
{
throw new Exception("needs to be less then 50 characters");
}
else
{
_hits = value.Trim();
}
}
}
public Musician()
{
//
// TODO: Add constructor logic here
//
}
}
First off, you should try using a List<string> rather than an ArrayList. ArrayList was what you used before C# added generics in version 2.0. List<T> allows you to retain typing information about the items in the list, which enables you to more easily write correct code.
The code you posted didn't seem to really match the details you were asking for, but something like this should do what you specified:
public class Musician
{
private List<string> _hits;
public string ListHits()
{
return string.Join(", ", _hits);
}
public void AddHit(string hit)
{
/*
* validate the hit
*/
_hits.Add(hit);
}
}
The key is using string.Join to convert the _hits list into a comma-delimited string. From there, the rest is just basic C# concepts.
Related
I'm constructing links in certain texts in my game, using the <link> tag with TMP. These links contains a GUID in order to identify what it is pointing to.
<link=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx>Some text</link>
This is working for my most part but when there a e in the GUID TMP cuts off at the first occurrence, so for example if there was an e at position 10 TMP only manages to return the 10 first characters in the GUID.
This is what happens:
xxxxxxxx-xxex-xxxx-xxxx-xxxxxxxxxxxx
xxxxxxxx-xx
The method generating the text
public string CharacterLink(CharacterInfo info)
{
return $"<color={characterColor.Format()}><link={info.Id}>{info.Fullname}</link></color>";
}
The methods for fetching the link
public Entity GetLinkCharacter(TextMeshProUGUI text)
{
TMP_LinkInfo info = GetLink(text);
if (info.Equals(default(TMP_LinkInfo)))
{
return null;
}
return entities.GetEntity(Guid.Parse(info.GetLinkID()));
}
private TMP_LinkInfo GetLink(TextMeshProUGUI text)
{
int index = TMP_TextUtilities.FindIntersectingLink(text, Input.mousePosition, null);
if (index == -1)
{
return default;
}
return text.textInfo.linkInfo[index];
}
Whenever there's an e in the GUID it throws an exception every time it tries to parse it since the GUID gets cut off on the first occurrence of an e.
The lack of quotation marks was the issue. Silly me forgot to add them.
public string CharacterLink(CharacterInfo info)
{
return $"<color={characterColor.Format()}><link={info.Id}>{info.Fullname}</link></color>";
}
had to be converted into this
public string CharacterLink(CharacterInfo info)
{
return $"<color=\"{characterColor.Format()}\"><link=\"{info.Id}\">{info.Fullname}</link></color>";
}
I've enabled the C# 8.0 non-nullable reference types feature in one of my projects, but now I'm unclear about how to represent missing data.
For example, I'm reading a file whose lines are colon-separated key/value pairs. Sometimes there's more than one colon on a line. In that case, the text before the first colon is the key, and the rest is the value. My code to parse each line looks like this:
public (string key, string value) GetKeyValue(string line)
{
var split = line.Split(':');
if (split.Length == 2)
return (split[0].Trim(), split[1].Trim());
else if (split.Length > 2)
{
var joined = string.Join(":", split.ToList().Skip(1));
return (split[0].Trim(), joined.Trim());
}
else
{
Debug.Print($"Couldn't parse this into key/value: {line}");
return (null, null);
}
}
What this does: If we have just one colon, return the key and value. If we have more than one, join the rest of the text after the first colon, then return the key and value. Otherwise we have no colons and can't parse it, so return a null tuple. (Let's assume this last case can reasonably happen; I can't just throw and call it a bad file.)
Obviously that last line gets a nullability warning unless I change the declaration to
public (string? key, string? value) GetKeyValue(string line)
Now in F# I would just use an Option type and in the no-colon case, I'd return None.
But C# doesn't have an Option type. I could return ("", ""), but to me that doesn't seem better than nulls.
In a case like this, what's a good way to say "I didn't find anything" without using nulls?
You could include if the result was successful in parsing by just returning a flag:
public class Result
{
private Result(){}
public bool Successful {get;private set;} = false;
public string Key {get; private set;} = string.Empty;
public string Value {get; private set;} = string.Empty;
public static Successful(string key, string value)
{
return new Result
{
Successful = true,
Key = key,
Value = value
};
}
public static Failed()
{
return new Result();
}
}
public Result GetKeyValue(string line){
return Result.Failed();
}
Then you could use it like
var result = GetKeyValue("yoda");
if(result.Successful)
{
// do something...
}
Alternatiely you could return 2 diffrent types and use pattern matching 👍
Actually, I realize now that part of the problem is that my method is doing two separate things:
Determine whether the line has a key.
Return the key and value.
Thus the return value has to indicate both whether there's a key and value, and what the key and value are.
I can simplify by doing the first item separately:
bool HasKey(string line)
{
var split = line.Split(':');
return split.Length >= 2;
}
Then in the method I posted, if there's no key, I can throw and say that the lines need to be filtered by HasKey first.
Putting on my functional thinking cap, an idiomatic return type would be IEnumerable<(string?,string?)>. The only change to your code would be to change return to yield return, and to remove the return statement if nothing is found.
public IEnumerable<(string? key, string? value)> GetKeyValue(string line)
{
var split = line.Split(':');
if (split.Length == 2)
return (split[0].Trim(), split[1].Trim());
else if (split.Length > 2)
{
var joined = string.Join(":", split.ToList().Skip(1));
yield return (split[0].Trim(), joined.Trim());
}
else
{
Debug.Print($"Couldn't parse this into key/value: {line}");
}
}
The caller then has several options on how to handle the response.
If they want to check if the key was found the old-fashioned eway, do this:
var result = GetKeyValue(line).SingleOrDefault();
if (!result.HasValue) HandleKeyNotFound();
If they prefer to throw an exception if the key is not found, they'd do this:
var result = GetKeyValue(line).Single();
If they just want to be quiet about it they can use ForEach, which will use the key and value if they are found and simply do nothing if they are not:
foreach (var result in GetKeyValue(line)) DoSomething(result.Item1, result.Item2);
Also, for what it's worth, I'd suggest using KeyValuePair instead of a tuple, since it clearly communicates the purpose of the fields.
I am working in .cs file and I need to see the output of some object/variable executed by the c# program. I will use that for debbuging purposes each time.
For example, in the code below, I need to see the output of the variable DataNaiss (type,number of rows,all elements included...).
var DataNaiss = engine.Evaluate("DataNaiss=DataIns[which(cond1 & DataIns$Id %in% ID_Final),'Date.naissance']").AsCharacter();
I tried to Add this code :
Console.WriteLine(DataNaiss.ToString());
Console.ReadLine();
The output is in this picture :
Just see the end line please R.net CharacterVector . It seems that it talk about the type of DataNaiss But where are all elements of it?
In other way, until now I don't know why I have also in the same console window the data of the table DataAch imported knowing that I just call console window for showing DataNaiss and not for other thing !! you can see in the same picture elements of the first table DataAch.
my code of importing data is:
REngine engine = REngine.GetInstance();
DataFrame DataAch = engine.Evaluate("DataAch=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/Achats1.csv',header=TRUE,sep =';',fill =TRUE)").AsDataFrame();
DataFrame DataDia = engine.Evaluate("DataDia=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/Diagnostic.csv',header=TRUE,sep =';',fill=TRUE)").AsDataFrame();
DataFrame DataCad = engine.Evaluate("DataCad=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/CADEAUX.csv',header=TRUE,sep =';',fill=TRUE)").AsDataFrame();
DataFrame DataIns = engine.Evaluate("DataIns=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/Inscrits.csv',header=TRUE,sep =';',fill =TRUE)").AsDataFrame();
How do you explain this please?
Just see the end line please R.net CharacterVector . It seems that it talk about the type of DataNaiss But where are all elements of it?
Calling .ToString() on a variable won't magically show all the data you need.
According to Microsoft Documentation you can see that:
The default implementation of the ToString method returns the fully qualified name of the type of the Object
Therefor, you can understand that the type of that variable called DataNaiss in your case is actually of type CharacterVector.
Looking at the source code of R.Net you can obviously see that the class CharacterVector doesn't override ToString method.
In order to get the elements of the variable DataNaiss you have to access them yourself. The only way I can see from the source code is to access them like DataNaiss[0] since in their source code you have:
public override string this[int index]
{
get
{
if (index < 0 || Length <= index)
{
throw new ArgumentOutOfRangeException();
}
using (new ProtectedPointer(this))
{
return GetValue(index);
}
}
set
{
if (index < 0 || Length <= index)
{
throw new ArgumentOutOfRangeException();
}
using (new ProtectedPointer(this))
{
SetValue(index, value);
}
}
}
I suggest you can loop over the DataNaiss object according to it's length, and grab the data you need, for example if you have access to Length property:
for (int i=0; i<DataNaiss.Length; i++)
{
Console.WriteLine(DataNaiss[i]);
}
This is not tested. I am answering all of this according to what I read in their code.
By overriding the ToString Function on the Types in the DataNaiss variable you can print them to the Console.
Following the MSDN Guide you do can do this like this:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Person: " + Name + " " + Age;
}
}
By then calling ToString() on the objects allows you to print them.
IDE: Visual Studio 2015 Update 3
Language: C# / .NET 4.5
Situation: Suppose I defined a class and I'm calling its properties tens of times, further let's suppose the class operates over one input given to the constructor and therefore it makes all operations except the first one redundant, because we already managed to calculate the return value the first time we called it.
Example of such property:
// let's call it a Month, because it extracts a month code from a string
private int Month
{
// there is only a getter
get
{
// here's my current strategy
// in the beginning of the class I set fMonth to -1
// it can only have possitive numbers, so if already set, I return it
if (fMonth > -1)
return fMonth;
// and here's the part I don't want to repeat
return fMonth =
Convert.ToInt32(SomeNumberString.Substring(2, 2));
}
}
Question: Is this the right strategy for not repeating the executive code?
Since the value for someNumberString is given to you in the constructor, you can use a readonly property.
ctor(string someNumberString)
{
Month = Convert.ToInt32(someNumberString.Substring(2, 2));
}
public Month { get; }
You are on the right track with using a private backing field fmonth for the property. You can further optimize this by moving the conversion code to an explicit set method. This removes the if check from every get access.
ctor(string someNumberString) {
SetMonth(someNumberString);
}
private int Month { get { return fmonth; } }
// -1 indicates that SetMonth() has never been called
private int fmonth = -1;
public void SetMonth(string someNumberString) {
fmonth = Convert.ToInt32(someNumberString.Substring(2, 2));
}
I add an indexer to my class. Is it proper coding to return null when the index doesn't exist? Then the consuming class would always have to check for null too. Is there a more elegant way?
public class ObjectList
{
private readonly ArrayList _objectList = new ArrayList();
public void Add(object value)
{
_objectList.Add(value);
}
public object this[int index]
{
get
{
if (CheckIndex(index))
return _objectList[index];
else
return null;
}
set
{
if (CheckIndex(index))
_objectList[index] = value;
}
}
private bool CheckIndex(int index)
{
if (index >= 0 && index <= _objectList.Count - 1 )
return true;
else
return false;
}
public int IndexOf(object value)
{
return _objectList.IndexOf(value);
}
}
class Program
{
static void Main(string[] args)
{
var oList = new ObjectList();
oList.Add("Some String");
oList.Add("new string");
//oList[1] = "Changed String";
Console.WriteLine("Index of new string = " + oList.IndexOf("new string"));
Console.WriteLine("Index of Some String = " + oList.IndexOf("Some String"));
Console.WriteLine("index 0 = {0} and index 5 = {1}", oList[0], oList[1]);
Console.WriteLine("Non-existing index 5 doesn't lead to crash when written to the console = {0} ", oList[5]);
if(oList[5]!=null)
Console.WriteLine("But when GetType is called on non-existing index then it crashes if not intercepted.", oList[5].GetType());
}
}
Also I wonder why doesn't the program crash when I write the value of an element to the console when it is null.
If I do not check for null when calling GetType() on it then it crashes, however.
How come?
the is "It depend"
1- when you build a libarary (for example DLL) and this dll is used by software that you do not know at all, or it is not already exits.
then the better is to throw an expcetion as the following
public object this[int index]
{
get {
if (index >= 0 && index <= _objectList.Count - 1 )
throw new IndexOutOfRangeException();
// your logic here .....
}
}
2- but if you build just a small class to use from anther place.
so you can follow the first way or you can return null.
public object this[int index]
{
get {
if (index >= 0 && index <= _objectList.Count - 1 )
return null;
// your logic here .....
}
}
and at that time you have to check the reference which returned by the indexer
but ( i prefer the first way, it is more clean)
The most normal way would be to throw an IndexOutOfRangeException. This is what the .NET builtin containers do, and many might expect the same behavior from a similar interface. As one might say, "it is better to ask for forgiveness than for permission."
However, the ArrayList object you use internally will already throw this if you try to access an invalid item. In addition, this overhead for bounds checking is already automatically done by the ArrayList itself, and so, in this situation, the index accessors should be simple wrappers around the ArrayList.
Another situation might be: What if I add null to your object? How could I then tell if an object I try to get in the future doesn't exist, or is just the value null? Exceptions fix this by interrupting the code flow so you can write code with the assumption that the code will work, but that you know what to do in the case of failure.