Consider this class
public class A
{
float Order
string Name
public A(float order, string name)
{
Order = order;
Name = name;
}
}
If I were to add this to a SortedSet<A> how would it know which member to order it by? How would I specify this, if I even can in the first place. I imagine that the best performance of the set would be sorting it on add, not adding then sorting through Sort().
SortedSet<A> will expect your class to implement IComparable<A>. Alternatively, you can supply a comparator of type IComparer<A> to do the ordering externally to your class, like this:
class ComparerForClassAByOrder : IComparer<A> {
public int Compare(A left, A right) {
return Math.Sign(left.Order-right.Order);
}
}
class ComparerForClassAByName : IComparer<A> {
public int Compare(A left, A right) {
return left.Name.CompareTo(right.Name);
}
}
Now you can create two sorted sets using different comparators:
var soredByOrder = new SortedSet<A>(new ComparerForAByOrder());
var soredByName = new SortedSet<A>(new ComparerForAByName());
Assuming that you change the accessibility so that you can read the members of A from outside the class, you can simply do:
new SortedSet<A>(Comparer<A>.Create((a1, a2) => a1.Order.CompareTo(a2.Order)))
This requires .NET 4.5 or later.
Remember that NaN will compare less than everything else.
If you do not pass in your own comparer to the constructor, it will be checked if each instance of A is of a run-time type which implements IComparable<> or IComparable. If not, an error is produced when adding to the SortedSet<A>.
Related
The Methode Array.Sort() has the following signature
public static void Sort (Array array, System.Collections.IComparer? comparer);
It looks like you need to pass an IComparer reference. But what is really needed is that array needs to implements IComparable, isn't it?
I see this syntax the first time. Is this common? How can I differentiate between a real parameter? Is there somewhere more information about this topic (in general)?
Important/Edit: ATM I'm reading a C# book and it says about Sort.Array (translated from German to English):
To the first parameter we pass the array to be sorted, in our case
arr. The second parameter is of type IComparer interface. Of course,
you can't pass an instance of type IComparer to the method call,
because interfaces are not instantiable. This is not how the type
specification of the second parameter should be understood. Instead,
the second parameter simply requires that the fist argument passed to
it be an object that implements the interface IComparer - whether the
object is of type DemoClass, Circle,
Basically he says that the second parameter is kind of a description for the first parameter. Is he correct or maybe that's just wrong and the source for my confusion?
https://openbook.rheinwerk-verlag.de/visual_csharp_2012/1997_04_008.html
I just implemented the following snippet. So this could be a way how to pass the second parameter, right?
Array.Sort(shapes, (a, b) => {
if (a.GetArea() < b.GetArea()) return -1;
else if (a.GetArea() > b.GetArea()) return 1;
return 0;
});
If you do not pass the comparer it will use the default comparer implementation for the Array items. But if you have a special comparer then you can pass your own custom Comparer to sort the elements.
Suppose you have a Class of Students (Array of Students), and your default Student comparer can be based on total marks. However, a maths teacher may want to sort the Students based on marks for the Maths only, in that case maths teacher can write his custom MathsRankComparer and pass it to the Sort method so that he will get the Students ordered by marks in Maths.
Similarly, English or Science teacher can pass the respective comparers to get their required ranking/ordering/sorting.
Hope this helps in understanding use of that overload.
Update: some examples to understand details.
public class Student: IComparable<Student>
{
public int ID { get; set; }
public string Name { get; set; }
public float TotalMarks { get; set; }
public float ScienceMarks { get; set; }
public float MathsMarks { get; set; }
public float EnglishMarks { get; set; }
public int CompareTo(Student other)
{
if (this.TotalMarks == other.TotalMarks)
return 0;
if (this.TotalMarks < other.TotalMarks)
return -1;
return 1;
}
}
public class MathsMarksBasedComparer : System.Collections.Generic.IComparer<Student>
{
public int Compare(Student a, Student b)
{
if (a.MathsMarks == b.MathsMarks)
return 0;
if (a.MathsMarks < b.MathsMarks)
return -1;
return 1;
}
}
public class EnglishMarksBasedComparer : System.Collections.Generic.IComparer<Student>
{
public int Compare(Student a, Student b)
{
if (a.EnglishMarks == b.EnglishMarks)
return 0;
if (a.EnglishMarks < b.EnglishMarks)
return -1;
return 1;
}
}
And finally, you can use them like this.
Student[] arr = new Student[100]; // Ignore this, you can use other styles of declaration
Array.Sort(arr, new EnglishMarksBasedComparer());
Array.Sort(arr, new MathsMarksBasedComparer());
Array.Sort(arr);
Basically he says that the second parameter is kind of a description for the first parameter. Is he correct or maybe that's just wrong and the source for my confusion?
It's not wrong it's just worded a bit confusingly.
The IComparer is a nullable type (defined by the questionmark at the end of IComparer). This states that the IComparer is optional/does not have to be passed. However as Mahesh Bongani already meantioned in his reply - internaly if you do not provide a comparer it takes the defualt comparer of the object.
So for this particular funtion if you would pass a Array with objects that do not implement a comparable the function wouldn't be able to sort the elements properly.
I have seen IComparer a few times and am unsure what implements it as standard - as far as lists, arrays and things go. I do know that numbers implement it and I think string does too.
You can though custom implement this inferface. If memory serves me correctly, it provides just one method (interface so you have to write logic yourself) that returns an int. -1 (<0) is lower ranked, +1(>0) is higher ranked, 0 is the same.
i've a Method which gets a List where T : Item.
How do i access the property from the Subclasses of Item?
private void CreateShopItem<T>(Transform itemTemplate, Transform shopScrollView, List<T> shopItemList)
where T : Item {
shopItemList.Name //this works
shopItemList.power //this is a property from the class cooling and i cant access it
}
Ive 4 subclasses from the base class Item but i can only access the properties from the Class Item
Item Class:
public class Item
{
public int Id;
public string Name;
public double Cost;
public Sprite Sprite;
public bool IsPlaced;
public Vector3 Position;
public Item()
{
Id = 0;
Name = "Default";
Cost = 0;
Sprite = null;
IsPlaced = false;
Position = Vector3.zero;
}
public Item(int id, string name, double cost, Sprite sprite, bool isPlaced, Vector3 position)
{
this.Id = id;
this.Name = name;
this.Cost = cost;
this.Sprite = sprite;
this.IsPlaced = isPlaced;
this.Position = position;
}
}
Sub Class Cooling:
public class Cooling : Item
{
public float power;
public float temp;
public Cooling(int id, string name, double cost, Sprite sprite, bool isPlaced, Vector3 position,
float power, float temp)
{
base.Id = id;
base.Name = name;
base.Cost = cost;
base.Sprite = sprite;
base.IsPlaced = isPlaced;
base.Position = position;
this.power = power;
this.temp = temp;
}
}
What would be a way to access the property of all subclasses from the Base Class?
Normally if a method needs to access a field/property this field would be included in the type that it accepts. While you can cast the item into a derived type, if you have to do it why accept the base type in the first place?
The problem is that if you use ifs or case when you add a new type you need to remember to come back to this piece of code and update it.
BTW. Use properties, not fields. It is the standard way:
public class Item
{
public int Id { get };
What you're asking the code to do doesn't make logical sense. When you use a generic type:
public class Foo<T>
{
public T Value { get; set; }
public void MyMethod()
{
// example code here
}
}
You are saying that you're going to be using a type (T) but you're not really sure yet which type you'll be using. The type will be specified at a later stage. The only assumption made by the compiler is that your T will derive from object.
This is okay, but that also means that you can't actually use this T with any more precision than you can use object. In the above example, you could call this.Value.ToString() because T is definitely an object (and object has the ToString() method), but you cannot call this.Value.Power because T is not known to be of the type Cooling (or a subtype).
You are able to influence what the compiler knows about the specific type that T will be. You've already done so by specifying that T will definitely be some sort of Item (i.e. class or subclass)
public class Foo<T> where T : Item
{
public T Value { get; set; }
public void MyMethod()
{
// example code here
}
}
Because the expectation is now that T is not just an object but also an Item, the compiler allows you to handle your T type with every known property/method of the Item type. You could access things like:
this.Value.Name
this.Value.Cost
this.Value.Sprite
Because these are properties of the Item class which you can definitely expect to see on any subclass of Item, you are allowed to access them when dealing with a T where T : Item generic type parameter.
You're trying to access a specific type's property (Cooling), without having told the compiler that your generic type is definitely going to be a (sub) class of Cooling.
That directly contradicts the core premise of using a generic type, i.e. treating a range of possible types using the same (generic) code. If that generic code were to only work with one specific type (i.e. Cooling), then there'd be no point in trying to make CreateShopItem work for any type that is not Cooling or one of its subtypes.
You need to go back to the drawing board with what it is that you want.
If I can assume that it is correct that CreateShopItem should work for any Item class, then you should inherently be able to write code that is able to handle any Item object without needing to know the specific concrete class being used.
I am very intentionally ignoring upcasting here because it's a bad approach that tries to cover for a bad design. Generic type upcasting is rarely a good idea. It violates OCP (in all but exceedingly rare examples), and would not be a good idea in this particular scenario anyway.
First of all the example that you show for the this one works and this one doesn't should be wrong because the reference that you are using is a List (List for your example) and the both of them will not work unless you get the element that you want to change from that list (with a loop or maybe with LINQ First() etc)
Secondly, If you want to access a field from a subclass while you have a base class object. You need to cast it to that subclass. For example:
class Item{
...
public int Id;
public string Name;
public double Cost;
}
class Cooling : Item {
...
public float power;
}
//Example method to call
private void CreateShopItem<T>(Transform itemTemplate, Transform shopScrollView, List<T> shopItemList)
where T : Item {
var firstItem = shopItemList().First(); // taking the first element just for example
firstItem.Name = "foo"; // this is fine
var coolingItem = (Cooling) firstItem;
coolingItem.power = 1000; // now this is also fine
}
This will fix your current case but I do not recommend to do it because as the subclasses increase this can turn into a big mess of casting disaster between classes.
I recommend to check out boxing/unboxing topic on C# for future use and best practices.
I have a double problem here. I need to sort a List<> that I know contains objects of a derived class to the class that the list was declared to contain originally. AND, I need to sort by the return value from a method in that derived class, which takes a parameter. Keep in mind that I already know the List contains objects all of the derived class type.
I've created some sample code here to demonstrate the question since the real code cannot be shared publicly. Note, I have no control over the base conditions here (i.e. the fact that the List<> collection's declared contents are the parent class and that it contains objects of the derived class, which contains a method that takes an argument and returns the values that I need to sort the collection by). So, I doubt I'd be able to use any suggestion that requires changes there. What I think I need is a way to specify (cast?) what is really in the List so I can access the method defined there. But I'm open to other thoughts for sure. Otherwise I'm left with a traditional bubble sort. Thanks.
public class Component
{
public int X;
public int Y;
}
public class ComponentList : List<Component>
{
// Other members that deal with Components, generically
}
public class Fence : Component
{
public int Distance(int FromX, int FromY)
{
int returnValue = 0;
// Caluclate distance...
return returnValue;
}
}
public class Yard : Component
{
// Yada yada yada
}
public class MyCode
{
public List<Component> MyFences;
public MyCode(List<Component> Fences, int FromX, int FromY)
{
// Sort the fences by their distance from specified X,Y
Fences.Sort((A as Fence, B as Fence) => A.Distance(FromX, FromY).CompareTo(B.Distance(FromX, FromY)));
// Or
List<Fence> sortedFences = MyFences.OrderBy(A => A.Distance(FromX, FromY)).ToList();
// Or ???
}
}
Use the Enumerable.Cast<Fence> extension method to transform your IEnumerable<Component> to IEnumerable<Fence>. Then I'd use your second approach (the OrderBy approach) to sort it, but that's my preference.
List<Fence> sortedFences = MyFences.Cast<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
This approach will throw if there is an object in MyFences that can't be cast to Fence. If you expect that the code should only be passed Fences, this might be what you want. If, instead, you want to skip over non-Fence members, you can use:
List<Fence> sortedFences = MyFences.OfType<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
I'm adding values to a c# generic list while trying to prevent duplicates, but without success. Anyone know of a reason why this code below wouldn't work?
I have a simple class here:
public class DrivePairs
{
public int Start { get; set; }
public int End { get; set; }
}
And here is my method which tries to return a generic list of the above class:
ArrayList found = DriveRepository.GetDriveArray(9, 138);
List<DrivePairs> drivePairs = new List<DrivePairs>();
foreach (List<int> item in found)
{
int count = item.Count;
if (count > 1)
{
for (int i = 0; i < (count - 1); i++)
{
DrivePairs drivePair = new DrivePairs();
drivePair.Start = item[i];
drivePair.End = item[i + 1];
if (!drivePairs.Contains(drivePair))
drivePairs.Add(drivePair);
}
}
}
drivePairs = drivePairs.Distinct().ToList();
As you can maybe see, I have an ArrayList, and each row contains a List<int>. What I'm doing is going through each and adding to a list which contains only pairs. E.g. if my List<int> contains [1,3,6,9] I want to add three entries to my pairs list:
[1,3]
[3,6]
[6,9]
It all works fine apart from not recognising duplicates. I thought this line would be enough:
if (!drivePairs.Contains(drivePair))
drivePairs.Add(drivePair);
but it continues to add them all. Even when I add a Distinct() at the end, it still doesn't remove them. I've also tried adding them to a HashSet, but it still includes all the duplicates.
Anyone know of a reason why the duplicates might not be getting picked up?
Your DrivePairs class does not specify equality, as a result, the Contains method will be using reference equality. Add an Equals method that uses both Start and End to determine equality and you will probably find your code works.
See: Equality Comparisons (C# Programming Guide)
List.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable.Equals method for T (the type of values in the list).
Change your DrivePairs class
public class DrivePairs: IEquatable<DrivePairs>
{
public int Start { get; set; }
public int End { get; set; }
public bool Equals(DrivePairs other)
{
return (this.Start == other.Start && this.End == other.End)
}
}
See: http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx
Hope this helps
You are creating new List<int> objects - these are different objects and when compared to each other, even if they contain identical values (in the same or in different orders), will be evaluated as different as the default comparison method on reference types is a reference comparison.
You need to write a custom comparer that will identify equal lists in the manner your application requires.
I've marked Colin's as the answer, but here was the code just in case it's any use to anyone:
Equality comparer:
public class EqualityComparer : IEqualityComparer<DrivePairs>
{
public bool Equals(DrivePairs x, DrivePairs y)
{
return x.StartHub.Equals(y.Start);
}
public int GetHashCode(DrivePairs obj)
{
return obj.Start.GetHashCode();
}
}
and in the controller:
IEqualityComparer<DrivePairs> customComparer = new EqualityComparer();
IEnumerable<DrivePairs> distinctDrivePairs = drivePairs.Distinct(customComparer);
drivePairs = distinctDrivePairs.ToList();
Thanks for all the help and comments
I have not tested it but I think the default equality test is if it is the same instance. Try overriding the Equals method and make it use your properties.
The DrivePairs class type is a reference type(remember reference type and value type concept). So when you check if DrivePairs varible is already added in List collections or not it return false as every DrivePairs varibale has different memory location from other.
Try using either Dictionary or StringDictionary or any other Key value pair collection. It will definately work.
I'm looking to use "phantom types" to implement type-safe identifiers. There's a question here about doing this in F#.
I'd like to do this in C#. How?
I've got a solution (which has problems), so I'll post it as a possible answer to see if anyone can improve it.
Why not make it a sealed class with its constructor private?
public sealed class Id<TDiscriminator>
{
private Id() { }
//some static methods
}
I've come up with the following:
struct Id<TDiscriminator>
{
private readonly Guid _id;
private Id(Guid id)
{
_id = id;
}
public Guid Value
{
get { return _id; }
}
public static Id<TDiscriminator> NewId()
{
return From(Guid.NewGuid());
}
public static Id<TDiscriminator> From(Guid id)
{
return new Id<TDiscriminator>(id);
}
public static readonly Id<TDiscriminator> Empty = From(Guid.Empty);
// Equality operators ellided...
}
...which I can use as follows:
class Order { /* empty */ }
class Customer { /* empty */ }
void Foo()
{
var orderId = Id<Order>.NewId();
var customerId = Id<Customer>.NewId();
// This doesn't compile. GOOD.
bool same = (orderId == customerId);
}
I don't particularly want concrete classes for the discriminator, because I don't want anyone instantiating them.
I could get around that by using an interface or an abstract class. Unfortunately, these can still be derived from and instantiated.
C# won't let you use a static class as a type argument. I can't say that I'm totally happy with the answers to that question, because the answers basically say "just because".
How about?
public sealed class Order
{
private Order() {}
}
public static sealed class Id<T>
{
// ...
}
I think that's exactly what you say. No one (except some special cases) can construct it and no one can inherit from it.
Well, as far as I could understand, you would like to provide a mechanism for distinguishing different types by a custom identifier object. I think you are almost near a working solution. In .NET when having a generic class, each substitution of the generic argument (or each unique combination of the generic arguments, if more than one) creates a unique type in the runtime. In your code Id<Order> and Id<Customer> are two distinct types. The NewId() method returns an instance of Id<Order> for the orderId and Id<Customer> for the customerId variables. The two types do not implement the == operator and therefore cannot be compared. Moreover, such comparison would be difficult to implement, since you cannot determine all possible uses of the Id<TDsicriminator> - you cannot guess what type will the TDsicriminator be substituted with.
1
A fast and simple solution will be to do this:
class Order { /* skipped */ }
class Customer { /* skipped */ }
void Foo()
{
var orderId = Id<Order>.NewId();
var customerId = Id<Customer>.NewId();
bool sameIds = (orderId.Value == customerId.Value); // true
bool sameObjects = orderId.Equals(customerId); // false
}
Since the Value properties are both of the Guid type, comparison is possible.
2
If you need however, to implement the == operator, or some sort of equality comparisons for instances of Id<TDisciminator>, the approach will be different. What comes up to my mind is the following:
public abstract class IdBase
{
public abstract Guid Value { get; protected set; }
public static bool operator == (IdBase left, IdBase right)
{
return left.Value == right.Value;
}
}
public sealed class Id<TDiscriminator> : IdBase
{
// your implementation here, just remember the override keyword for the Value property
}
Many people would not recommend the second approach though, since different implementations of IdBase may happen to have the same Value property (if you used the constructor that passes an existing ID). For instance:
var guid = Guid.NewGuid();
var customerID = Id<Customer>.From(guid);
var orderID = Id<Order>.From(guid);
Here (customerID == orderID) will then return true which is probably not what you want.
Shortly, in such a case, two different types will count as equal, which is a big logical mistake, so I'd stick to the first approach.
If you need Id<Customer>.Value to always be different than Id<Order>.Value, because of the different generic arguments (Customer is different than Order), then the following approach will work:
public sealed class Id<in TDiscriminator>
{
private static readonly Guid _idStatic = Guid.NewGuid();
private Id()
{
}
public Guid Value
{
get { return _idStatic; }
}
}
Notice the in keyword used here. This is applicable for .NET 4.0 where generics can be covariant and ensures that your class uses contravariant generics. (see http://msdn.microsoft.com/en-us/library/dd469487.aspx). In the above code, the _idStatic field will have a unique value for every different type supplied as a generic argument.
I hope this info is helpful.