Is there a specific reason that we have to refer to the properties in a Tuple as Item1, Item2 etc. This just seems like a bad idea to me as they could easily get mixed up in your code. Wouldn't it be much more meaningful to be able to name your properties ie. Red, Green, Blue?
If you want names, don't use Tuples.
Anonymous type:
var t = new { Green = 1, Red = "nice" };
if (t.Green > 0) ....
The Tuple<...> classes are just normal C# classes. C# does not provide a way to have dynamically-named properties (aside from just using a Dictionary or a dynamic object like ExpandoObject). However, C# does provide something like what you want via anonymous types:
var x = new { Red = 10, Blue = 20, Green = 30 }
var sum = x.Red + x.Blue + x.Green;
The reason anonymous types work is that they are just a convenient syntax for defining a custom tuple class on the fly.
These have the advantage of acting like named tuples, but have the disadvantage of not being nameable by the programmer (so you can't make a method that explicitly returns an anonymous type).
If you want to do this then create a class with the appropriately named properties. A tuple is just a quick and dirty way of avoiding having to write a class or use out params when you want to return multiple values from a method.
A tuple is not supposed to contain any meaningful properties. It is just a disposable set of items bunched together in a group.
If you want meaningful property names, make a type with those properties. You can either write a class from scratch and use that class, or use anonymous types.
You could define the class like this (with generics) if you will always be partial to Red/Blue, otherwise, you can use anonymous types as suggested by others.
class RedBluePair<T1, T2>
{
private T1 _Red;
private T2 _Blue;
public RedBluePair(T1 red, T2 blue)
{
_Red = red;
_Blue = blue;
}
public T1 Red { get { return _Red;} }
public T2 Blue { get { return _Blue;} }
}
Reproducing my answer from this post as now it is possible to give names to properties in Tuples.
Starting C# v7.0 now it is possible to name the tuple properties which earlier used to default to names like Item1, Item2 and so on.
Naming the properties of Tuple Literals:
var myDetails = (MyName: "RBT_Yoga", MyAge: 22, MyFavoriteFood: "Dosa");
Console.WriteLine($"Name - {myDetails.MyName}, Age - {myDetails.MyAge}, Passion - {myDetails.MyFavoriteFood}");
The output on console:
Name - RBT_Yoga, Age - 22, Passion - Dosa
Returning Tuple (having named properties) from a method:
static void Main(string[] args)
{
var empInfo = GetEmpInfo();
Console.WriteLine($"Employee Details: {empInfo.firstName}, {empInfo.lastName}, {empInfo.computerName}, {empInfo.Salary}");
}
static (string firstName, string lastName, string computerName, int Salary) GetEmpInfo()
{
//This is hardcoded just for the demonstration. Ideally this data might be coming from some DB or web service call
return ("Rasik", "Bihari", "Rasik-PC", 1000);
}
The output on console:
Employee Details: Rasik, Bihari, Rasik-PC, 1000
Creating a list of Tuples having named properties
var tupleList = new List<(int Index, string Name)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
foreach (var tuple in tupleList)
Console.WriteLine($"{tuple.Index} - {tuple.Name}");
Output on console:
1 - cow
5 - chickens
1 - airplane
I hope I've covered everything. In case, there is anything which I've missed then please give me a feedback in comments.
Note: My code snippets are using string interpolation feature of C# v7 as detailed here.
Yes, You can name tuple properties from C# 7.0.
From this documentation,
You can explicitly specify the names of tuple fields either in a tuple initialization expression or in the definition of a tuple type, as the following example shows:
(int Red, int Green, int Blue) ColorRGB = (0, 0, 255);
// Or
var ColorRGB = (Red: 0, Green: 0, Blue: 255);
Or,
If you don't specify a field name, it may be inferred from the name of the corresponding variable in a tuple initialization expression, as the following example shows:
int Red = 0;
int Green = 0;
int Blue = 255;
var ColorRGB = (Red, Green, Blue);
Related
In my scenario I have a class called Person. I need to test if certain people are compatible or not and return a bool value. I was thinking of using an enum setup to make it easier to test these compatibility tests. However I'm not familiar with enum and was hoping someone could shed some light or help demonstrate how i would use it in my case.
I was thinking it would be easiest to assign an id to each Person and a compatibility list along with that ID. Below is some pseudo code demonstrating what i mean. I'm just not clear on how to to set this up using enums.
ID's assigned to each class object
1 = Person(John)
2 = Person(Kevin)
3 = Person(Michelle)
4 = Person(Krystal)
5 = Person(Leslie)
Compatibility lists
1 = [2,4]
2 = [1,3,5]
3 = [2,5]
4 = [1]
5 = [2,3]
The tests I want to Perform and return a bool value.
If (Person(John) compatible with Person(Krystal))
{return true}else{return false}
Honestly, an enum is not the solution for this. The closest analogy to your "compatibility checker" would probably be an EqualityComparer<T> in .NET. It's a separate class.
The comparison "are two people compatible" really doesn't belong in the Person class. It depends on what measure of compatibility you are comparing them and over time that comparison may change or you may add other compatibility comparers.
So, instead of an enum create a CompatibilityComparer class. For now this has one method .IsCompatible(Person a, Person b) and inside that method you can use a dictionary, database lookup, complex calculation based on weighted values from a and b, or whatever else you want.
private static readonly CompatibilityComparer comparer
= new CompatibilityComparer();
...
if (comparer.IsCompatible(john, krystal)) ...
See separation of concerns and single responsibility principle.
Ideally your comparer would also operate on an interface IPerson rather than the concrete class Person so you can test it more easily with mock IPerson objects.
A simplest example, using a Dictionary of compatible people might be:
Dictionary<int, int[]> matrix = new Dictionary<int, int[]>();
// You could initialize this statically, or better yet, use Lazy<>
static CompatibilityComparer()
{
matrix[1] = new[] { 2, 4 };
...
}
public bool IsCompatible(Person a, Person b)
{
return matrix[a.Id].Contains(b.Id);
}
You could also represent your graph of compatibility as a list of pairs of compatible people ids, as a 2D square matrix, or any other graph representation.
If you really do have all the Person objects in memory, statically defined, it would be better to have a Dictionary<Person, List<Person>> although at some point one has to ask, "what's the real environment here?", it's not an interesting problem until there are thousands of People and they are in a database and then a different approach is needed again.
How was 'compatibility' decided? a) by a person entering data in a database or b) by some algorithm? If the former then that would involve Ids and a 'compatibility' table in the database with two foreign keys back to the people table (like the dictionary is meant to illustrate). And if the latter why isn't that in code?
I would suggest you to use enums together with extension methods. Let me explain how this would work for you.
public enum Person
{
John = 1,
Kevin = 2,
Michelle = 3,
Krystal = 4,
Leslie = 5
}
Here you have identifiers with an associated number set explicitly. However, this number association is optional and can be elided.
public static class PersonExtensions
{
private Dictionary<Person,List<Person>> compatiblePersons = createCompatiblePersons();
private static Dictionary<Person,List<Person>> createCompatiblePersons()
{
var d = new Dictionary<Person,List<Person>>;
// put your compatibilities here
d[Person.John] = new List()
{
Person.Kevin,
Person.Krystal
};
return d;
}
public static List<Person> GetCompatiblePersons(this Person person)
{
return compatiblePersons(person);
}
public static bool IsCompatibleWith(this Person person, Person other)
{
return this.GetCompatiblePersons().Contains(other);
}
}
This static class allows to use extension methods on any Person instance, e.g. Person.John.IsCompatibleWith(Person.Michelle) will return false in this case. The association is made in the Dictionary declared above. This technique allows you to add "properties" to your enums like the ability to ask for compatibility or get the list of compatible persons. However, i would suggest to choose a class if it gets more complex than this.
The answer of #OwlSolo in contrast does the job but is somewhat limited, but if your requirements are just as described I would recommend just adding a convenience extension method, which hides the logical bit calculations and take the [Flags] approach.
Code written blindly, so no warranties for compilation errors
What you want is an enum type with the flags attribute:
[Flags]
enum MyCompatibilities
{
a = 1,
b = 2,
c = 4,
d = 8
}
With this you can assign a number of enum elements that apply.
MYCompatibility comp = MYCompatibility.a | MYCompatibility.b;
| is a logical OR and it means that your variable comp has the properties a as well as b
You can find out whether a certain compatibility is set via bit comparison:
if (comp & MYCompatibility.a= != 0)
or with the logic provided by the [Flags] attribute:
if (comp.HasFlag(MYCompatibility.a))
For the inner workings of this, google for bit flags.
Say I have
List<int> ages = new List<int>() { 8, 5, 3, 9, 2, 1, 7 };
List<int> marks = new List<int>() { 12, 17, 08, 15, 19, 02, 11 };
I can sort my marks by ages like this:
while (true)
{
bool swapped = false;
for (int i = 0; i < ages.Count - 1; i++)
if (ages[i] > ages[i + 1])
{
int tmp = ages[i];
ages[i] = ages[i + 1];
ages[i + 1] = tmp;
tmp = marks[i];
marks[i] = marks[i + 1];
marks[i + 1] = tmp;
swapped = true;
}
if (!swapped)
break;
}
Now I want to put this into a function that accepts any two lists. The first parameter will be the reference list, the numerical or comparable list. The second parameter will be the list containing the data.
For example:
public static void Sort<T>(List<T> RefList, List<T> DataList)
{
// sorting logic here...
}
There are a few problems:
First of all, T is almost certainly not the same type in RefList and DataList. RefList might be dates, integers, or doubles; whereas DataList is free to be absolutely anything. I need to be able to receive two, arbitrary generic types.
Secondly, I cannot seem to use the > operator with the T in this line:
if (ages[i] > ages[i + 1])
Perhaps my whole approach is wrong.
By the way, I have read responses to similar questions that suggest that the two lists should be combined into a single list of a compound data type. This isn't practical at all for my application. All I want to do is write a static function that somehow sorts one list based on the elements of another.
To sort one list the way you want you actually need to somehow keep references from items in first list to they weight/keys in the second list. No existing methods do that as you can't easily associate metadata with arbitrary values (i.e. if first list is list of int as in your case there is nothing to map to keys in second list). Your only reasonable option is to sort 2 lists at the same time and make association by index - again no existing classes to help.
It may be much easier to use solution that you reject. I.e. simply Zip and OrderBy, than recreate first list:
ages = ages
.Zip(marks, (a,m)=> new {age = a; mark = m;})
.OrderBy(v => v.mark)
.Select(v=>v.age)
.ToList();
Note (courtesy of phoog): if you need to do this type of sorting with Array there is Array.Sort that allows exactly this operatiion (see phoog's answer for details).
There's no framework method to do this with List<T>, but if you don't mind putting the data into two arrays, you can use one of the Array.Sort() overloads that takes two arrays as arguments. The first array is the keys, and the second is the values, so your code might look like this (leaving aside the step of getting arrays from the lists):
Array.Sort(ages, marks);
The specifics of getting the values into arrays and then back into lists would depend, among other things, on whether you need to end up with the same list sorted appropriately or whether it's okay to return a new list with the data in the desired order.
Use:
public static void Sort<TR, TD>(IList<TR> refList, IList<TD> dataList)
where TR : System.IComparable<TR>
where TD : System.IComparable<TD>
{
...
}
and then use:
refList[i].CompareTo(refList[i+1])
instead of the operators.
.Net numbers already implement IComparable, and you can use overloads that allow you to specify a different IComparable.
If I understand "I can sort my marks by ages like this:" properly,
I would like to suggest the below to eliminate much confusion.
struct Student{
int age;
int marks;
};
List<Student> students = {{8,12}, ...};
Now you can sort according to age and marks is accordingly sorted automatically.
If it is not possible, you need to fix the code as below.
First of all, T is almost certainly not the same type in RefList and DataList.
Then you need 2 parameters T1, T2. Just T implies the types are the same.
public static void Sort<RefType, DataType>(List<RefType> RefList, List<DataType> DataList)
{
You can also zip the two lists together as suggested by Mechanical Snail and explained in Looping through 2 Lists at once
I get from an input a group of double variables named: weight0, weight1...weight49.
I want to dynamically insert them into a double Array for easier manipulation.
But instead of calling each one like: Weights[0] = weight0...Weights[49] = weight49 I want to do it with a single loop.
Is there a way to do it?
No, basically - unless you mean at the same time that you create the array:
var weights = new[] {weight0, weight1, weight2, ... , weight48, weight49};
Personally, I'd be tempted to get rid of the 50 variables, and use the array from the outset, but that may not be possible in all cases.
you could use reflection to determine the index of the array from the variable names but this is far from efficient. See this post for details.
I would try to do it with a KeyValuePair- Listobject
// sample data
var weight = 1.00;
// create a list
var tmp = new List<KeyValuePair<string,object>>();
// Here you can add your variables
tmp.Add(new KeyValuePair<string,object>("weights" + tmp.Count.ToString()
, weight));
// If needed convert to array
var weights = tmp.ToArray();
// get the information out of the array
var weightValue = weights[0].Value;
var weightKey = weights[0].Key;
I think this will give you all the options, you might need for the array. Give it a try.
I'm putting this up because you can do it - so long as these variables are actually fields/properties. Whether you should is another matter - this solution, while reusable, is slow (needs delegate caching) and I have to say I agree with Marc Gravell - consider using an array throughout if you can.
If the variables are properties then it needs changing. Also if you need to write the array back to the variables in one shot (because this solution generates an array with copies of all the doubles, I wouldn't consider creating an object array with boxed doubles), that requires another method...
So here goes. First a holy wall of code/extension method:
//paste this as a direct child of a namespace (not a nested class)
public static class SO8877853Extensions
{
public static TArray[] FieldsToArray<TObj, TArray>(this TObj o,string fieldPrefix)
{
if(string.IsNullOrWhiteSpace(fieldPrefix))
throw new ArgumentException("fieldPrefix must not null/empty/whitespace",
"fieldPrefix");
//I've done this slightly more expanded than it really needs to be...
var fields = typeof(TObj).GetFields(System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic)
.Where(f =>f.Name.StartsWith(fieldPrefix) && f.FieldType.Equals(typeof(TArray)))
.Select(f =>new{ Field = f, OrdinalStr = f.Name.Substring(fieldPrefix.Length)})
.Where(f => { int unused; return int.TryParse(f.OrdinalStr, out unused);})
.Select(f => new { Field = f.Field, Ordinal = int.Parse(f.OrdinalStr) })
.OrderBy(f => f.Ordinal).ToArray();
//doesn't handle ordinal gaps e.g. 0,1,2,7
if(fields.Length == 0)
throw new ArgumentException(
string.Format("No fields found with the prefix {0}",
fieldPrefix),
"fieldPrefix");
//could instead bake the 'o' reference as a constant - but if
//you are caching the delegate, it makes it non-reusable.
ParameterExpression pThis = Expression.Parameter(o.GetType());
//generates a dynamic new double[] { var0, var1 ... } expression
var lambda = Expression.Lambda<Func<TObj, TArray[]>>(
Expression.NewArrayInit(typeof(TArray),
fields.Select(f => Expression.Field(pThis, f.Field))), pThis);
//you could cache this delegate here by typeof(TObj),
//fieldPrefix and typeof(TArray) in a Dictionary/ConcurrentDictionary
return lambda.Compile()(o);
}
}
The extension method above will work on any type. It's generic over both the instance type and desired array type to simplify the creation of the lambda in code - it doesn't have to be generic though.
You pass in the name prefix for a group of fields - in your case "weight" - it then searches all the public and private instance fields for those with that prefix that also have a suffix which can be parsed into an integer. It then orders those fields based on that ordinal. It does not check for gaps in the ordinal list - so a type with weight0 and weight2 would work, but would only create a two-element array.
Then it bakes a dynamic piece of code using Expression trees, compiles it (at this point, as mentioned in the code, it would be good to cache the delegate against TObj and TArray for future use) and then executes it, returning the result.
Now add this to a test class in a standard unit test project:
private class SO8877853
{
private double field0 = 1.0;
private double field1 = -5.0;
private double field2 = 10.0;
public double[] AsArray()
{
//it would be nice not to have to pass both type names here - that
//can be achieved by making the extension method pass out the array
//via an 'out TArray[]' instead.
return this.FieldsToArray<SO8877853, double>("field");
}
}
[TestMethod]
public void TestThatItWorks()
{
var asArray = new SO8877853().AsArray();
Assert.IsTrue(new[] { 1.0, -5.0, 10.0 }.SequenceEqual(asArray));
}
Like I say - I'm not condoning doing this, nor am I expecting any +1s for it - but I'm a sucker for a challenge :)
Hi before going to direct problem let me show my code :
//Definition of enum
public enum LogType
{
Warning = -2,
Error = -1,
Info = 0,
EruCtorDtor = 1,
Notifications = 2,
CommunicationWithAOT = 4,
ExecutedOrder = 8,
ERUInfo = 16,
DebugLog = 32,
}
//Use of enum
CurrentLogFlagSettings = nLogFlag;
LogFlagMap = new SortedDictionary<LogType, int>();
ulong mask = 1;
while(mask <= nLogFlag)
{
if ((nLogFlag & mask) == mask)
{
LogType type = (LogType)mask; //Step 1
string val = type.ToString(); //Step 2
//Processing the value
LogFlagMap.Add(type, tempVal)
LogMsg(val + " added", type);
}
mask <<= 1;
}
What I want is : Process step2 only after step1 has produced valid value. I mean value should be between range defined in enum definition. Otherwise I dont want to process it.
for e.g.
case 1 - Lets say mask value is 32,
its defined in enum. So type is
getting value DebugLog and so it
type.ToString() (i.e. "DebugLog"),
this is a valid case.
case 2- Lets
say mask value is 128 and its not
defined in enum, in this case I dont
want to process anything on 128
value. But what is happening its
geting value 128 in type and
type.ToString() is converting it
into 128. I dont want this, I want
to make sure whether 128 belongs to
enum values or not.
I want to prevent 2nd case to be executed. Is there any solution for my problem?
Please let me know if more details are needed.
You could use Enum.IsDefined, like so:
int value = 128;
Console.WriteLine(Enum.IsDefined(typeof(LogType), value)); // will print out False
Firstly, let me seriously apologise, Ive had like no sleep, so if I missed the point a little. Please, just ignore me.
You can enumerate your LogType with Enum.GetValues(typeof(LogType))), so you could step through and check a value against it. I had some code, but, I couldnt promise it compiled.
Bool isValid(int i)
{
foreach (LogType l in Enum.GetValues(typeof(LogType)))
{
if ((int)l == i) return true;
}
return false;
}
You can also use Enum.GetValues(typeof(LogType)) to get all the possible values for your enum and do what you want through that.
i.e.
var values = Enum.GetValues(typeof (LogType));
foreach (LogType type in values)
{
if (((int)type & nLogMask) == (int)type)
{
//value is valid, process the value
}
}
One addition to your code could be the addition of the [Flags] attribute to you enum, this then makes it clear that the enum values are for bitwise operations
e.g.
[Flags]
public enum LogType
{
Warning = -2,
Error = -1,
Info = 0,
EruCtorDtor = 1,
Notifications = 2,
CommunicationWithAOT = 4,
ExecutedOrder = 8,
ERUInfo = 16,
DebugLog = 32,
}
although to do this, you would need to change the values such that the Warning and Error take the top 2 bits of the enum value (assuming this is still necessary).
The c# Enum class also has the method GetName(). This might provide a nice and easy manner to retrieve the name of the value set
e.g.
Enum.GetName( typeof(LogType), 4 ); // result = CommunicationWithAOT
I have a library called Unconstrained Melody which allows you to express all of this in a type-safe generic way and avoids boxing too. Personally I prefer that over using Enum.IsDefined, but obviously that doesn't involve learning an extra library.
It's probably not worth using Unconstrained Melody if this is the only thing you need to do with your enum, but if you've got other similar operations, you may wish to consider it.
Example:
public int foo(int x, int optionalY = 1, int optionalZ = 2) { ... }
I'd like to call it like this:
int returnVal = foo(5,,8);
In other words, I want to provide x and z, but I want to use the default for Y, optionalY = 1.
Visual Studio does not like the ,,
Please help.
If this is C# 4.0, you can use named arguments feature:
foo(x: 5, optionalZ: 8);
See this blog for more information.
In C# 4.0 you can name the arguments occurring after skipped defaults like this:
int returnVal = foo(5, optionalZ: 8);
This is called as named arguments. Several others languages provide this feature, and it's common form them to use the syntax foo(5, optionalZ=8) instead, which is useful to know when reading code in other languages.
Another dynamic way to supply parameters of your choise is to implement your method(s) in a class and supply named parameters to the class constructor. Why not even add calls to methods on same line of code as mentioned here : How to define named Parameters C#
var p = new PersonInfo { Name = "Peter", Age = 15 }.BuildPerson();
This is a late answer, but for the people who get into this.
One could also use Overloads,that uses the same name as the method/function, but with a different set of parameters.
ea
int SummAll (int a=0, int b=1, int c=2)
{return a+b+c;}
int SumAll (int a=0;int c=10) //skipping B
{return a+c; }
This pattern equals how with intellicense we can browse through variations of functions.