How does List<T>.IndexOf() search? - c#

Haven't found a definite answer on this so I'm going to ask it here. Sorry if I missed something.
Say we have this class
internal class MyClass
{
public MyClass()
{
}
private string my_field;
public string MyField
{
get { return my_field; }
set { my_field = value; }
}
}
and we create a List<MyClass> like this and populate it with testing info
List<MyClass> my_list = new List<MyClass>();
private void TestFunction()
{
MyClass mc = new MyClass();
mc.my_field = "test1";
my_list.Add(mc);
}
My question is, will IndexOf() return the real index of mc if I create an identical MyClass object with the same my_field value? If not, why ?
private void SearchList()
{
MyClass mc = new MyClass();
mc.my_field = "test1";
int index = my_list.IndexOf() // WILL THIS RETURN THE INDEX OF THE PREVIOUSLY ADDED "mc" OBJECT
}

I will post this here as it may help someone somewhere.
Thanks to the comments I understood how IndexOf() works.
Basically the method uses the Equals() method to find the matching object and return the index of the provided object.
Here is the relevant documentation from msdn
List.IndexOf Method

Related

The type name ____ does not exist in the type ____

I know the question is already out there. But i cant solve my problem with the other solutions. I want to create a List out of Lists.
My Code:
class SomeClassName
{
static List<char> saveFields = new List<char>();
public static List<char> SaveFields
{
get { return saveFields; }
set { saveFields = value; }
}
}
public void someMethod
{
List<SomeClassName.SaveFields> someListName = new List<SomeClassName.SaveFields>();
}
My Namespace is TicTacToe so there is no name issue.
How can i solve this error?
I get the error for "SaveFields"
SomeClassName.SaveFields isn't a type, it is a property. The type of that property is List<char>. If you want to create a variable with the same type, you have to use List<char>.
You can assign that value to the variable though:
public void someMethod()
{
List<char> someListName = SomeClassName.SaveFields;
}
Have you tried using generics?
class SomeClassName
{
static List<T> saveFields = new List<T>();
public static List<T> SaveFields
{
get { return saveFields; }
set { saveFields = value; }
}
}
It is insanely good, useful but machine resource hunger, use carefully

How to reference an existing class variable using a string?

I want to get a reference to an existing class variable using a string. I have seen some examples of similar things but can seem to figure this one out.
Please help with the commented section!
public class MyClass
{
public int myInt;
public MyClass( int i)
{
myInt = i;
}
}
void Start ()
{
MyClass myclass = new MyClass(1);
MyClass myOtherClass = //Should be equal to myClass BUT I want to use the string "myClass" to reference it.
}
Local variables cannot be accessed by string name, even using reflection. One option is to store them in a dictionary:
var dict = new Dictionary<string, MyClass>();
dict.Add("myClass", myClass);
string varName = "myClass";
MyClass myOtherClass = dict[varName];
But it's not clear at all why you want to access it by string name. I suspect there's a better solution for your real problem.
Though the question is kind of weird, but here is the stupid solution:
var instances = new Dictionary<string, MyClass>();
MyClass instance= new MyClass(1);
//the string "instance" can be replaced with "nameof(instance)" using C# 6.0
instances.Add("instance", instance);
To access this instance by name:
MyClass myOtherInstance = instances["instance"];
Wierd question, curious to know if this is what you wanted:
public class MyClass
{
public int myInt;
public MyClass(int i)
{
myInt = i;
}
}
public class Starter
{
private MyClass myclass;
public void Start()
{
myclass = new MyClass(1);
var type = this.GetType();
var variable = type.GetField("myclass", BindingFlags.NonPublic | BindingFlags.Instance);
MyClass myOtherClass = (MyClass)variable.GetValue(this);
}
}

In C#, what's the simplest approach to late initialize an instance field?

I have a class with 5-6 fields that should be initialized once after the constructor runs.
public OriginalFileProcessor(IConfigManager configManager)
{
this._configManager = configManager;
this._field1 = this._configManager.GetAppSetting<int>ConfigKeys.Key1);
this._field2 = this._configManager.GetAppSetting<int>ConfigKeys.Key2);
this._field3 = this._configManager.GetAppSetting<int>ConfigKeys.Key3);
this._field4 = this._configManager.GetAppSetting<int>ConfigKeys.Key4);
this._field5 = this._configManager.GetAppSetting<int>ConfigKeys.Key5);
}
But I don't like to write logic apart from just simple assignments in the constructor.
I can't use inline initialization for field1 for example since then I can't use the _configManager instance there:
private int readonly _field1 = this._configManager.GetAppSetting<int>ConfigKeys.Key1);
If I use a readonly property then I'd have to add extra code like this:
private int? _field1;
public int Property1
{
get
{
if (!this._field1.HasValue)
{
this.__field1 = this._configManager.GetAppSetting<int>(Key1);
}
return this._field1.Value;
}
}
Is there any simpler approach for late initialization of instance fields?
Lazy<T> is a good option as suggested.
What I usually use is the following...
Providing your _field* is a nullable
In your property you can do...
return this.__field1 ?? (this.__field1 = this._configManager.GetAppSetting<int>(Key1));
EDIT:
Given comments discussion - why not just use a non static approach over Lazy<T>, e.g.
private readonly Lazy<int?> _field;
// init in ctor
_field = new Lazy<int?>(() => YourFieldInit(""));
// use in property
return _field.Value ?? 0;
EDIT 2:
And a small test to clarify the Lazy behavior:
public class DoLazy
{
Lazy<int?> _field;
public DoLazy()
{
// 'lazy' gets initialized - but `YourFieldInit` is not called yet.
_field = new Lazy<int?>(() => YourFieldInit(""));
}
int Property
{
get
{
// `YourFieldInit` is called here, first time.
return _field.Value ?? 0;
}
}
int? YourFieldInit(string test)
{ // breakpoint here
return -1;
}
public static void Test()
{
var lazy = new DoLazy();
int val1 = lazy.Property;
var val = lazy.Property;
}
}
Put a breakpoint inside the YourFieldInit - to see when it's actually called.
Call DoLazy.Test() from your e.g. Main.

How to pass in the "modifier" string returned by the function?

class test
{
public String get() {return s;}
private String s="World";
}
class modifier
{
public static void modify(ref String v)
{
v+="_test";
}
}
String s1="Earth";
modifier.modify(ref s1); <-------- OK
test c=new test();
modifier.modify(ref c.get()); <------- Error
How to pass in the "modifier" string returned by the function?
Assignment through another String object is unacceptable. So how will the copy is created.
You're trying to write C++ code in C#. You'll need to approach this the C# way.
Add a property for test.s, instead of a method called "get()".
We'll call this new property "MyString" in the code below:
class test
{
public String MyString
{
get
{
return s;
}
set
{
s = value;
}
}
private String s = "World";
}
class modifier
{
public static string modify(String v)
{
return v + "_test";
}
}
test c = new test();
c.MyString = modifier.modify(c.MyString);
If you dont like Matthew Watson's answer and you want to stay to your approach, the way to go is by using StringBuilder.That is a String that can change its value without creating a new one!
What i mean:
Normal String's value cant be changed, what is happening is that a new String is being created....and the pointer(that points to the String you want to change its value) points from now on to this new String. All other pointers....that "were pointing" to the old String .....are still pointing...to the old String!(the String's value didnt change!)
I am not sure if thats clear enough but you have to understand this if you want to play with Strings.This is exactly why s1 cant change its value.
The workaround is with StringBuilder:
class test
{
public StringBuilder get() { return s; }
private StringBuilder s = new StringBuilder("World");
}
class modifier
{
public static void modify(StringBuilder v)
{
v.Append("_test");
}
}
And some test code : (of course all this comes with processing cost...but i dont think that will be an issue for now)
StringBuilder s1 = new StringBuilder("Earth");
System.Diagnostics.Debug.WriteLine("earth is {0}", s1);
modifier.modify(s1); //<-------- OK
System.Diagnostics.Debug.WriteLine("earth is {0}",s1);
test c=new test();
StringBuilder aa=c.get();
System.Diagnostics.Debug.WriteLine("earth is {0}", aa);
modifier.modify(aa); //<------- Error(not anymore)
System.Diagnostics.Debug.WriteLine("earth is {0}", c.get());
Before you use the code try to understand how String and StringBuilder works
You have to create a temporary variable:
string tmp = c.get();
modifier.modify(ref tmp);
Because you are passing your parameter by reference.
The class test is designed such that its field s can't be reassigned (changed to point to a new object) from outside the class. That's because s is private, and the get() method only returns s, hence can't reassign it.
Either change the class test to allow the outside world to reassign s somehow, or use reflection to access a private field from the outside.
You can use a property with a get/set-eccessor and then pass to the modify() a test object:
class test
{
public String myString
{
get { return s; }
set { s = value; }
}
private String s="World";
}
class modifier
{
public static void modify(test myTest)
{
myTest.myString += "_test";
}
}
test c = new test();
modifier.modify(c);
Console.WriteLine(c.myString); //World_test

Accessing object properties from string representations

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 :-)

Categories