This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I have a custom collection and I want to overload the indexer. My problem is that I get a compile time error even though the signatures are different.
public HeaderLine this[LineNumber lineNum]
{
get
{
return (HeaderLine)InnerList[(int)lineNum - 1];
}
set
{
InnerList[(int)lineNum] = (HeaderLine)value;
}
}
public HeaderLine this[int lineNum]
{
get
{
return (HeaderLine)InnerList[lineNum - 1];
}
set
{
InnerList[lineNum - 1] = (HeaderLine)value;
}
}
}
And when I simply try to implement this:
MessageBox.Show(myDatafile.Header[3].Description);
These are the errors:
ERROR The best overloaded method match for 'XXX.Header.this[XXX.LineNumber]' has some invalid arguments
ERROR Argument '1': cannot convert from 'int' to 'XXX.LineNumber'
I'm starting to think that you can't overload an indexer multiple times? Or what am I doing wrong where this doesn't work. I KNOW WORKAROUNDS such as XXX.Header[(LineNumber)myIntegerValue], but I'd really like it to be VERY novice friendly. Thank you.
EDIT LineNumber is an enum
LONG EDIT Here is my custom collection class (sorry if too long I didn't know what would be necessary)
namespace XXX
{
public class HeaderLines : CollectionBase
{
public void Add(HeaderLine newHeaderLine)
{
List.Add((HeaderLine)newHeaderLine);
}
public void Remove(HeaderLine newHeaderLine)
{
List.Remove((HeaderLine)newHeaderLine);
}
public HeaderLine this[LineNumber lineNum]
{
get
{
return (HeaderLine)InnerList[(int)lineNum - 1];
}
set
{
InnerList[(int)lineNum] = (HeaderLine)value;
}
}
public HeaderLine this[int lineNum]
{
get
{
return (HeaderLine)InnerList[lineNum - 1];
}
set
{
InnerList[lineNum - 1] = (HeaderLine)value;
}
}
}
}
namespace XXX
{
public class HeaderLine
{
public string Description { get; set; }
public override string ToString()
{
return Description;
}
}
}
EDIT: I feel so sorry to waste everyones time. I found my problem and it was a stupid mistake. I'm just beginning to teach myself through reading. What happened was the class that held the collection didn't correctly implement the indexers. Sorry.
You most definitely can overload indexers (and plenty of system types do so). Here's an example which compiles without problem:
using System;
class Foo
{
public string this[string text]
{
get { return text; }
}
public int this[int number]
{
get { return number; }
}
}
class FooHolder
{
public Foo Foo { get; set; }
}
class Test
{
static void Main()
{
var holder = new FooHolder { Foo = new Foo() };
int x = holder.Foo[10];
string y = holder.Foo["hello"];
}
}
See whether you can come up with a similar short but complete program which fails, and we can work out why. At the moment there are too many unknowns to easily diagnose the problem.
Here is an example that again shows multiple indexers, but also shows it doing the enum conversion like you are doing and it works, you can copy and paste this into LinqPad to run it.
We need more info about your code.
public void Main()
{
DaClass thing = new DaClass();
Console.WriteLine(thing[1]);
Console.WriteLine(thing[Magic.Two]);
}
public class DaClass
{
private List<string> stuff = new List<string>{"Item1", "Item2", "Item3", "Item4"};
public string this[Magic m]
{
get{return stuff[(int)m];}
set{stuff[(int)m] = value;}
}
public string this[int i]
{
get{return stuff[i];}
set{stuff[i] = value;}
}
}
//Results
//Item2
//Item3
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last year.
Improve this question
I am trying everything I can but the object is not getting deserialized, I tried almost all the possible solutions to the problem but nothing is working, if someone can help that would be great.
please see below is the code snippet for the code
it always returns a null value to me.
using System;
using System.Text.Json;
namespace ConsoleApp8
{
class Program
{
static void Main(string[] args)
{
var a = "{\"enrollmentType\":\"draft\",\"emrName\":\"accuro\",\"emrVersion\":\"v1\",\"workflowType\":\"coordinator\"}";
var x = "{\"enrollmentType\":\"draft\",\"emrName\":\"accuro\",\"emrVersion\":\"v1\",\"workflowType\":\"coordinator\"}";
string json = #"{""id"":10,""name"":""Name"",""revisionDate"":1390293827000}";
var ed = JsonSerializer.Deserialize<EnrollmentExtension>(x);
//.Replace("'", "\"")
if (!string.IsNullOrWhiteSpace(ed.emrName))
{ }
}
}
public class EnrollmentExtension
{
#region MyRegion
private string _emrName;
private string _emrVersion;
private string _workflowType;
private string _enrollmentType; public bool IsDraft()
{
return (string.Compare(_enrollmentType, "draft", true) == 0);
}
#endregion
public string enrollmentType
{
get { return _enrollmentType; }
private set { _enrollmentType = value; }
}
public string workflowType
{
get { return _workflowType; }
private set { _workflowType = value; }
}
public string emrVersion
{
get { return _emrVersion; }
private set { _emrVersion = value; }
}
public string emrName
{
get { return _emrName; }
private set { _emrName = value; }
}
public void SetWorkflowType(string workFlowType)
{
_workflowType = workFlowType;
}
}
public class Test
{
public EnrollmentExtension myprop { get; set; }
}
}
you have a bug in your classes, all your setters are private, but should be public. all properties should be like this
public string enrollmentType
{
get { return _enrollmentType; }
set { _enrollmentType = value; }
}
or you can keep the private setters but create a constructor
public EnrollmentExtension(string enrollmentType, ... and so on, string workflowType)
{
_enrollmentType=enrollmentType;
_workflowType=workflowType;
... and so on
}
My brain is gonna to explode. :) So I would like to get help from you.
Please, think about my question like about just programmer puzzle. (Actually. perhaps it is very easy question for you, but not for me.)
It is needed to create array of objects. For example List where T is class. (I will describe Class T below). Also it is needed create “container” that will contain this array and some methods for work with this array. For example Add(), Remove(int IndexToRemove).
Class T must have field "Container", this way each elements of our array would be able to know where is it contained and has access its container's fields and methods. Notice, that in this case Class T should have type parameter. Indeed, it is not known beforehand which container's type is used.
Let us denote this class container as A and class element (class T) as AUnit.
Code:
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Add();
a.Units[0].SomeField +=100;
Console.ReadKey();
}
}
class A
{
public List<AUnit> Units;
public A()//ctor
{
Units = new List<AUnit>();
}
public void Add()
{
this.Units.Add(new AUnit(this));
}
}
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
}
Public fields should be protected or private of course, but let think about this later.
You can ask “why we create public A Container field in AUnit”? We create field public string Name{get;private set;} (actually property but nevermind). And also we would like to be able to change value of this field for example method [Class AUnit] public bool Rename(string newName)();. The main idea of this method is changing Name field only that case if no one element in array (public List Units; ) has the same name like newName. But to achieve this, Rename method has to have access to all names that is currently used. And that is why we need Container field.
Code of extended version AUnit
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (AUnit unt in this.Container.Units)
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
Ok. If you still read it let's continue. Now we need to create Class B and class BUnit which will be very similar like Class A and Class Aunit. And finally the main question of this puzzle is HOW WE CAN DO IT? Of course, I can CopyPaste and bit modify A and AUnit and create this code.
class B
{
public List<BUnit> Units; //Only Type Changing
public B()//ctor Name changing...
{
Units = new List<BUnit>();//Only Type Changing
}
public void Add()
{
this.Units.Add(new BUnit(this));//Only Type Changing
}
}
class BUnit
{
public int SomeField;
public B Container;//Only Type Changing
public string Name { get; private set; }
public A a; //NEW FIELD IS ADDED (just one)
public BUnit(B container) //Ctor Name and arguments type changing
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
this.a=new A(); //New ROW (just one)
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (BUnit unt in this.Container.Units) //Only Type Changing
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
And I can to use this classes this way.
static void Main(string[] args)
{
B b = new B();
b.Add();
b.Units[0].a.Add();
b.Units[0].a.Units[0].SomeField += 100;
bool res= b.Units[0].a.Units[0].Rename("1");
res = b.Units[0].a.Units[0].Rename("1");
Console.ReadKey();
}
This construction is can be used to create “non-homogeneous trees”.
Help, I need somebody help, just no anybody…. [The Beatles]
I created B and BUnit using CopyPaste.
But how it can be done using “macro-definitions” or “Generic”, inherit or anything else in elegant style? (C# language)
I think that there is no reason to describe all my unsuccessful attempts and subquestions. Already topic is too long. : )
Thanks a lot if you still read it and understand what I would like to ask.
You need to implement a base type, lets call it UnitBase, with all common functionality. I'd structure your code the following way:
Create an interface for your container, this way you can change implementation to more performant solutions without modifying the elements you will be adding to the container.
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
}
Following the idea stated in 1, why not make the search logic belong to the container? It makes much more sense, as it will mostly depend on how the container is implemented:
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
bool Contains(string name);
}
A specific implementation of IContainer could be the following:
public class Container : IContainer
{
public Container()
{
list = new List<UnitBase>();
}
private List<UnitBase> list;
public Q Add<Q>() where Q: UnitBase, new()
{
var newItem = Activator.CreateInstance<Q>();
newItem.SetContainer(this);
list.Add(newItem);
return newItem;
}
public IEnumerable<UnitBase> Units => list.Select(i => i);
public bool Contains(string name) =>
Units.Any(unit => unit.Name == name);
}
Create a base class for your AUnit and BUnit types condensing all common functionality:
public abstract class UnitBase
{
protected UnitBase()
{
}
public IContainer Container { get; private set; }
public int SomeField;
public string Name { get; private set; }
public void SetContainer(IContainer container)
{
Container = container;
}
public bool Rename(String newName)
{
if (Container.Contains(newName))
return false;
this.Name = newName; //No need to use String.Copy
return true;
}
}
Implement your concrete types:
public class BUnit : UnitBase
{
public int SpecificBProperty { get; private set; }
public BUnit()
{
}
}
Shortcomings of this approach? Well, the container must be of type <UnitBase>, I've removed the generic type because it really wasn't doing much in this particular case as it would be invariant in the generic type.
Also, keep in mind that nothing in the type system avoids the following:
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();
If having two different types in the same container is not an option then this whole set up kind of crumbles down. This issue was present in the previous solution too so its not something new, I simply forgot to point it out.
InBetween , I am very thankful to you for your advices. Actually I can't say that I understood your answer in full, but using your ideas I have done what I want.
Looks like my variant works well. However I would like to hear your (and everyone) opinions about code described below. The main goal of this structure is creating non-homogeneous trees. So could you estimate it from this side.
First of all. We need to create interfaces for both classes. We describe there all "cross-used" functions.
public interface IUnit<T>
{
string Name { get;}
void SetContainer(T t);
bool Rename(String newName);
}
public interface IContainer
{
bool IsNameBusy(String newName);
int Count { get; }
}
Next. Create Base for Unit Classes for future inheritance. We will use in this inheritors methods from Container Base so we need generic properties and IUnit interface.
class UnitBase<T> : IUnit<T> where T : IContainer
Unfortunately I don't know yet how to solve the problem with Constructor parameters. That is why I use method
SetContainer(T container).
Code:UnitBase
class UnitBase<T> : IUnit<T> where T : IContainer
{
protected T Container;
public string Name { get; private set; }
public UnitBase()
{
this.Name = "Default";
}
public void SetContainer(T container)
{
this.Container = container;
}
public bool Rename(String newName)
{
bool res = Container.IsNameBusy(newName);
if (!res) this.Name = String.Copy(newName);
return !res;
}
}
Next. Create ContainerBase
ContainerBase should:
1) has IContainer interface.
2)has information about what it will contain:
... where U : IUnit<C>, new()
3)and .... has information about what itself is. This information we need to pass as parameter to SetContainer() method.
Code ContainerBase:
class ContainerBase<U, C> : IContainer //U - Unit Class. C-Container Class
where U : IUnit<C>, new()
where C : ContainerBase<U, C>
{
protected List<U> Units;
public U this[int index] { get { return Units[index]; } }
public ContainerBase()//ctor
{
this.Units = new List<U>();
}
public void Add()
{
this.Units.Add(new U());
this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
}
public bool IsNameBusy(String newName)
{
bool res = false;
foreach (var unt in this.Units)
{
if (unt.Name == newName)
{
res = true;
break;
}
}
return res;
}
public int Count { get { return this.Units.Count; } }
}
Cast ((TContainer)(this)) may be is a bit strange. But using ContainerBase we always should use NewInheritorContainer. So this cast is just do nothing…looks like...
Finally. This classes can be used like in this example.
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}
class SheetUnit : UnitBase<SheetContainer>
{
public CellContainer Cells;
public PictureContainer Pictures;
public SheetUnit()
{
this.Cells = new CellContainer();
this.Pictures = new PictureContainer();
}
}
class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }
class CellUnit : UnitBase<CellContainer>
{
public string ValuePr;//Private Field
private const string ValuePrDefault = "Default";
public string Value//Property for Value
{
//All below are Just For Example.
get
{
return this.ValuePr;
}
set
{
if (String.IsNullOrEmpty(value))
{
this.ValuePr = ValuePrDefault;
}
else
{
this.ValuePr = String.Copy(value);
}
}
}
public CellUnit()
{
this.ValuePr = ValuePrDefault;
}
}
class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }
class PictureUnit : UnitBase<PictureContainer>
{
public int[,] Pixels{get;private set;}
public PictureUnit()
{
this.Pixels=new int[,]{{10,20,30},{11,12,13}};
}
public int GetSizeX()
{
return this.Pixels.GetLength(1);
}
public int GetSizeY()
{
return this.Pixels.GetLength(0);
}
public bool LoadFromFile(string path)
{
return false;
}
}
static void Main(string[] args)
{
SheetContainer Sheets = new SheetContainer();
Sheets.Add();
Sheets.Add();
Sheets.Add();
Sheets[0].Pictures.Add();
Sheets[1].Cells.Add();
Sheets[2].Pictures.Add();
Sheets[2].Cells.Add();
Sheets[2].Cells[0].Value = "FirstTest";
bool res= Sheets[0].Rename("First");//res=true
res=Sheets[2].Rename("First");//res =false
int res2 = Sheets.Count;
res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
res2 = Sheets[2].Pictures.Count;//1
res2 = Sheets[1].Pictures.Count;//0
res2 = Sheets[0].Pictures[0].GetSizeX();//3
Console.ReadKey();
}
Looks like it works like I want. But I didn’t test it full.
Let me say Thank you again, InBetween.
This was from my university C# - windows forms exam, im trying to resolve some old subjects, but i seem to find myself stuck in this situation. This is my code:
abstract class CarFile
{
private string marca;
private readonly string serie;
public CarFile(string marca, string serie)
{
this.marca = marca;
this.serie = serie;
}
public string GetMarca
{
get { return this.marca; }
set { this.marca = value; }
}
public string GetSerie
{
get { return this.serie; }
}
public abstract string GetDescriere();
}
Then I have to do this:
my second class called ServiceFile : CarFile, ICloneable. in this class i have an array or list of strings called RepairComands which contains the necessary repairs.
- a private atribute called "motor" which can only take the following vallues {gas,gpl,hibrid} .
- a constructor which throws a generic exception if "serie==null"
-overrides the abrstract method getDescriere() to return the complete description of the car file
this is my code:
public class MyException : System.Exception
{
public MyException(string mesaj) : base(mesaj) { }
}
class ServiceFile : CarFile, ICloneable, IComparable, IReparabil
{
string[] RepairComands;
private enum motor { motorina, benzina, GPL, electric, hibrid };
public ServiceFile(string serie, string marca, string[] RepairComands):base(serie,marca){
if (serie == null)
{
throw new MyException("MESAJ");
}
this.RepairComands = RepairComands;
}
//not sure if this is correct
public override string GetDescriere()
{
string msj = string.Format("the car {0} with serial {1} and necess. repairs {2}", this.GetMarca, this.GetSerie, this.RepairComands);
return msj;
}
public object Clone()
{
ServiceFile clone = new ServiceFile(this.GetSerie, this.GetMarca, this.RepairComands);
return clone;
}
//implemented IComparable to be able to compare here 2 files by the number of repairs needed
public int CompareTo(object obj)
{
ServiceFile altafisa = (ServiceFile)obj;
if (this.RepairComands != altafisa.RepairComands)
return 1;
else return 0;
}
//overloads ToString to return the complete file description
public override string ToString()
{
return this.GetMarca + " "+ this.GetSerie + " " + this.RepairComands;
}
}
}
so far so good. this actually works.
but my problem comes now:
I have to define the interface IRep which contains 2 methods : void RepairCar() and void AddRepair(string repair).
THen ServiceFile class implements : IRep, and the function RepairCar() will be used for removing the last repair from the collection RepairComands
and the function AddRepair(string repair) will be used to add a repair in the collection RepairComands.
(For allowing the access to the private list of Repairs we should overload the index operator[] )
Thank you so much for your help, I'm a beginnes in C# and just wanted to understand better this subject that was given in my class so i could learn
Thank you
I need a little pattern direction here. New to C#.
I'm working with a third-party development kit that wraps a web service. There are two specific classes I deal with that, while relatively similar, are in two different namespaces in the dev kit and there's no common base class. I'd like to program against a common interface for them both however. I haphazardly threw together an implementation that essentially wraps the wrapper, but I feel rather certain it's not the most efficient method due to the incessant type casting.
I've been digging through articles on adapters, interfaces, extension methods, etc., but I'm running low on time, so if I could get a push in one direction that'd be greatly appreciated.
using ThirdParty.TypeA.Employee;
using ThirdParty.TypeB.Employee;
public class Employee
{
private object genericEmployee;
private EmployeeType empType;
public enum EmployeeType
{
TypeA = 0;
TypeB = 1;
}
public Employee(Object employee, EmployeeType type)
{
genericEmployee = employee;
empType = type;
}
public String Name
{
if (empType == EmployeeType.TypeA)
return (ThirdParty.TypeA.Employee)genericEmployee.Name;
else
return (ThirdParty.TypeB.Employee)genericEmployee.Name;
}
public String Age
{
if (empType == EmployeeType.TypeA)
return (ThirdParty.TypeA.Employee)genericEmployee.Age;
else
return (ThirdParty.TypeB.Employee)genericEmployee.Age;
}
}
Rev 2:
class EmployeeTypeAAdapter : TypeA, IEmployeeAdapter
{
TypeA _employee;
public EmployeeTypeAAdapter(TypeA employee)
{
_employee = employee
}
public String Name
{
get { return _employee.Name; }
set { _employee.Name = value; }
}
public String Balance
{
get
{
if (_employee.Balance != null)
{
decimal c = _employee.Balance.Amount;
return String.Format("{0:C}", c);
}
else
{
return "";
}
}
}
//...
}
class EmployeeTypeBAdapter : TypeB, IEmployeeAdapter
{
TypeB _employee;
public EmployeeTypeAAdapter(TypeB employee)
{
_employee = employee
}
public String Name
{
get { return _employee.Name; }
set { _employee.Name = value; }
}
public String Balance
{
get
{
if (_employee.Balance != null)
{
decimal c = _employee.Balance.Amount;
return String.Format("{0:C}", c);
}
else
{
return "";
}
}
}
//....
}
Try this approach:
public interface IEmployeeAdapter
{
string Age { get; set; }
string Name { get; set; }
}
class EmployeeTypeAAdapter : TypeA, IEmployeeAdapter
{
public EmployeeTypeAAdapter(TypeA employee) { }
}
class EmployeeTypeBAdapter : TypeB, IEmployeeAdapter
{
public EmployeeTypeBAdapter(TypeB employee) { }
}
public static class EmployeeAdapterFactory
{
public static IEmployeeAdapter CreateAdapter(object employee, EmployeeType type)
{
switch (type)
{
case EmployeeType.TypeA: return new EmployeeTypeAAdapter((TypeA)employee);
case EmployeeType.TypeB: return new EmployeeTypeBAdapter((TypeB)employee);
}
}
// or without enum
public static IEmployeeAdapter CreateAdapter(object employee)
{
if (employee is TypeA) return new EmployeeTypeAAdapter((TypeA)employee);
if (employee is TypeB) return new EmployeeTypeABdapter((TypeB)employee);
}
// or better introduce sort of type map
}
Another proper name is EmployeeProxy, as you prefer.
What you're trying to do is known as Duck typing. You can do this using adapter classes and a shared interface, but creating these adapters manually requires a lot of repetitive glue code. One way you can get around writing the glue code is to construct the adapter type dynamically. You can do this yourself via IL Emit (a worthwhile exercise if you've never had a chance to play with it before, though there can be quite a few boundary cases to consider.) If you're just interested in getting it working, however, you might check out this project as a place to start. The C# 'dynamic' type could also be used (and winds up doing some of the same code generation behind the scenes), but it doesn't give you a reference you can pass around to non-dynamic code as if it were an interface type.
I've got a custom object (example only code for ease of understanding) ...
public class MyClass
{
private string name;
private int increment;
private Guid id;
public string Name
{
get { return name; }
set { name = value; }
}
public int Increment
{
get { return increment; }
set { increment = value; }
}
public Guid Id
{
get { return id; }
set { id = value; }
}
}
... and a custom collection of this class ...
public class MyClassCollection : Collection<MyClass>
{
}
I was looking to write a Sort routine for the collection which will have the following public method ...
public void Sort(params string[] sortProperties)
{
if (sortProperties == null)
{
throw new ArgumentNullException("sortProperties", "Parameter must not be null");
}
if ((sortProperties.Length > 0) && (Items.Count > 1))
{
foreach (string s in sortProperties)
{
// call private sort method
Sort(s);
}
}
}
... and the private Sort method would take a parameter of the property name ...
private void Sort(string propertyName)
{
}
What I want to do is be able to pass in a set of property names into the method ...
MyClassCollection current = new MyClassCollection();
// setup a objects in the collection
current = GetCollectionData();
// sort by Name, then by Increment
current.Sort("Name", "Increment");
Using the property names passed into the method I want to be able to check to see if it has a property of that name, if so work out what type it is and then run through a sort of it.
The interim workaround which I have currently got is ...
private void Sort(string propertyName)
{
// convert to List
List<MyClass> myCurrentClass = Items as List<MyClass>;
// sort
if (myCurrentClass != null)
{
switch (propertyName)
{
case "Name":
myCurrentClass.Sort(delegate(MyClass myClassOne, MyClass myClassTwo)
{
return
Comparer<string>.Default.Compare(myClassOne.Name,
myClassTwo.Name);
}
);
break;
case "Increment":
myCurrentClass.Sort(delegate(MyClass myClassOne, MyClass myClassTwo)
{
return
Comparer<int>.Default.Compare(myClassOne.Increment,
myClassTwo.Increment);
});
break;
}
}
}
... but ideally I would like to switch on the underlying type of the Property (string, int etc.) and using a distinct number of delegate calls for the types for sorting. I've looked around but I've not found anything which points me in the right direction. I've had a look at reflection but I couldn't see anything which would be able to help me.
Is this even possible? and if so, how?!
Cheers!
Reflection would be the way to go - look at Type.GetProperty(string name). Creating the right comparer might be tricky after that - you might want to write a generic method, and then invoke that with reflection based on the property type. It all gets pretty icky, I'm afraid - but it's definitely feasible.
private void Sort( string propertyName )
{
List<MyClass> myCurClass = ...
myCurClass.Sort(delegate( MyClass left, MyClass right ){
PropertyInfo lp = typeof(MyClass).GetProperty (propertyName);
Comparer.Default.Compare (pi.GetValue(left), pi.GetValue(right));
});
}
I think this should get you started. :)
(Not tested, nor compiled, but you'll get the idea)
After hitting my head against the problem for a while and hoping on a train home last night I decided that I would try and bash out an answer. Using a combination of Jon's pointers and Frederik's use of the PropertyInfo class and keeping the original idea of switching on the underlying object type, this is what I came up with ...
private void Sort_version2(string propertyName)
{
// convert to list
List<MyClass> myCurrentClass = Items as List<MyClass>;
string typeOfProperty;
PropertyInfo pi;
// sort
if ((myCurrentClass != null) && (MyClass.HasDetailAndExtract(propertyName, out typeOfProperty, out pi)))
{
switch(typeOfProperty)
{
case "System.String":
myCurrentClass.Sort(delegate(MyClass one, MyClass two)
{
return
Comparer<string>.Default.Compare(pi.GetValue(one, null).ToString(),
pi.GetValue(two, null).ToString());
});
break;
case "System.Int32":
myCurrentClass.Sort(delegate (MyClass one, MyClass two)
{
return
Comparer<int>.Default.Compare(
Convert.ToInt32(pi.GetValue(one, null)),
Convert.ToInt32(pi.GetValue(two, null)));
});
break;
default:
throw new NotImplementedException("Type of property not implemented yet");
}
}
}
I've documented the thought process and more details on my blog let me know what you think!
Thanks to Jon and Frederik for the help :-)