How to pass string into collection by reference? - c#

It seems that string is reference, but copied by value
List<string> data = new List<string>();
string s = "a";
data.Add(s); // copy by value??
s = "b";
Console.WriteLine(data[0]); // "a"
It also seems that class is reference copied by reference
class boxstring { public string val; }
List<boxstring> data = new List<boxstring>();
boxstring s = new boxstring { val = "a" };
data.Add(s); // copy by reference, ok
s.val = "b";
Console.WriteLine(data[0].val); // "b"
Is there a simpler way to pass string into collection by reference without wrapping it into class? I'd like to pass object member into collection and if the object is changed, the collection should be also changed without writing extra code.

Strings are immutable, if you want the objects in your container to change, they must be mutable. Therefore, you must wrap them in a class like you did.

Strings are immutable. Whenever you assign new value to string variable, a new instance is created everytime that's why you can't see the updates in your collection.
However, .NET already provide mutable counterpart of string i.e. "StringBuilder". This will work for you -
List<StringBuilder> data = new List<StringBuilder>();
StringBuilder s = new StringBuilder("a");
data.Add(s);
s.Clear();
s.Insert(0, "b");
Console.WriteLine(data[0]); // "b"

Here's an idea to make you code simpler :
public MyString
{
public string Value{get;set;}
public MyString(string value)
{
Value=value;
}
public static implicit operator MyString(string value)
{
return new MyString(value);
}
public static implicit operator string(MyString mystring)
{
if(mystring==null) return null;
return mystring.Value;
}
then you can use MyString object whenever you want to have string by reference.since we have these implicit operator in place you can use MyString instead of string

You cannot pass intrinsic data-types by reference, they are always passed by value.
Intrinsic types include basic types like Int32, String, Bool, etc..

Related

C# return (dynamic or anonymous?) object with return values from other methods as properties

I would like to return an object, which stores the return values from other class methods as properties on the return object. The problem is that I do not know which is the best way to do this in C#. Currently I am using a sort of JavaScript-ish approach. Because I do not know the return type, I use the dynamic keyword.
class Test {
public static dynamic MyExportingMethod() {
return new {
myString = MyStringMethod(),
myInt = MyIntMethod()
};
}
public static string MyStringMethod() {
return "Hello";
}
public static int MyIntMethod() {
return 55;
}
}
And then being able to access them like so,
var myReturnObjWithProps = Test.MyExportingMethod();
myReturnObjWithProps.myString; // should be "Hello"
So my questions are, should I use the dynamic return type? Am I not just returning an anonymous object?
should I use the dynamic return type?
Yes - a method that returns dynamic effectively returns an object, so you have to use dynamic in order to access it's properties at runtime without reflection.
Am I not just returning an anonymous object?
You are, but the declared type of the method is effectively object so its properties cannot be referenced at compile-time.
Bottom line - you should avoid returning anonymous types from methods if at all possible. Use a defined type, or keep the creation and usage of the anonymous type in one method so you can use var and let the compiler infer the type.
Make a class for the return type. You want something strongly typed, both for performance and for clarity.
class Foo
{
string MyString { get; set}
int MyInt { get; set}
}
class Test
{
public static Foo MyExportingMethod()
{
return new Foo
{
MyString = MyStringMethod(),
MyInt = MyIntMethod()
};
}
public static string MyStringMethod()
{
return "Hello";
}
public static int MyIntMethod()
{
return 55;
}
}
You should use dynamic sparingly. This way anyone can see what your method is returning. If you return dynamic the caller has no way of knowing what to look for in the dynamic without looking at the source for your method. That way the abstraction goes away and well-structured programming is all about abstraction.
An alternative to creating a new class simply for a method return would be ValueTuple:
public static (string myString, int myInt) MyExportingMethod()
{
return (MyStringMethod(), MyIntMethod());
}
var (myString, myInt) = Test.MyExportingMethod();
myString; // == "Hello"

How to access methods of subclass in object array C#?

How can I set/get the value of an object in an object array?
Currently I get:
"object does not contain a definition for 'value' and no extension method"
Example C#;
public class myObjClass
{
public int value = 5;
}
public class myObjClass2
{
public float[] pos = new float[2];
}
public void test()
{
myObjClass myObj = new myObjClass();
myObjClass2 myObj2 = new myObjClass2();
object[] objArr = new object[2];
objArr[0] = myObj;
objArr[1] = myObj2;
Debug.Print(myObj.value.ToString());
Debug.Print(objArr[0].value.ToString()); // how?
}
Its because a generic object does not have the property value your class myObjClass has. To fix this you could cast the item to your class like so:
((myObjClass)objArr[0]).value.ToString()
Only do this ^ if you are sure of the type
Instead you could also check it first:
With as:
var item = objArr[0] as myObjClass;
if( item != null ) // Item will be null if its not a 'myObjClass'
{
//Do stuff with item
}
Or with is:
if( objArr[0] is myObjClass )
{
var item = (myObjClass)objArr[0];
//Do stuff with item
}
When using an object array you have to cast to the real type (here: myObjClass) before accessing the fields:
You can access the object like this
((myObjClass)objArr[0]).value
but I would not recommend. CanĀ“t you have your array to be the concrete type
var array = new myObjClass[42]
A compact safe alternative to retrieve the value is
(objArr[0] as myObjClass)?.value
You need to cast object to known type which is myObjClass, like:
((myObjClass)objArr[0]).value.ToString();
Or you can use reflection
var valueString = objArr[0].GetType().GetProperty("value").GetValue(objArr[0]);
Debug.Print(valueString.ToString());
Hope helps,
Technically you can put it as
Debug.Print((objArr[0] as myObjClass)?.value.ToString());
We try casting objArr[0] as myObjClass and if succeed get value and turn it to string. If objArr[0] is not myObjClass we return null as a string
However, a much better way is to implement ToString() in both classes of interest:
public class myObjClass
{
public int value = 5;
public override string ToString() {
// When debugging we want to know "value"
return value.ToString();
}
}
public class myObjClass2
{
public float[] pos = new float[2];
public override string ToString() {
// When debugging we want to know "pos[0]" and "pos[1]" values
return $"{pos[0]} : {pos[1]}";
}
}
And then put an easy
// Just print out debug info (we don't want to know the actual objArr[0] class)
Debug.Print(objArr[0].ToString());
You have a single object, that indeed is an instance of myObjClass, and has a value field, but you have two references to it.
One (myObj) is known to the compiler to be of type myObjClass, and it can guarantee that it has a value field.
The other (objArr[0]) is only known to the compiler to be of type object, and it cannot guarantee that it has a value field.
For example, you could do:
objArr[0] = (random.Next() > 0.5) : myObj ? myObj2
where we're gonna decide at runtime, based on the value of a random number, which will be the type of the actual object at objArr[0].
So, if this was allowed, half of the time objArr[0].value would be correct, and half of the time it will be an error.

How do I cast a concatenated string to a Class.Property?

I have a static class with several static strings used to store constant values. For example, Foo.Bar might return a string representing database column name and Foo.Foo might return a string with an epoch value.
In my application, I need to concatenate the class name with the name of the string to get the value I need. For example, I know the class name is Foo. I also know the property name is Bar. However the property name changes based on another value. In a foreach, I'm concatenating the class name with the other property name to get a string "Foo.Bar". So far we're okay. When I pass the concatenated string into my method that takes a string, it does not retrieve the static string from the class. In other words, even though the concatenated string is formed correctly as "Foo.Bar", my method does not return the value of Foo.Bar. If I hardcode Foo.Bar I get the string I need but this really needs to be done a runtime.
Any thoughts on how I can fix this? Can I cast this to something?
public static class Foo
{
public static string Bar = "Sample Text";
}
public class Program
{
static void Main()
{
// string "Foo.Bar" is built here by combining two strings.
...
// more processing
...
// I need the literal value of Foo.Bar here not literally "Foo.Bar"...
}
}
If Foo is always the class, then you could just pass in the name of the property instead of the concatenated string:
public string GetString(string propertyName)
{
return typeof(Foo).GetProperty(propertyName).GetValue(null, null);
}
If it's not always Foo, you could pass in the type to the GetString() method also.
Reflection...
Consider:
public class Foo
{
public string Bar { get; set; }
}
You can do:
Foo a = new Foo() { Bar = "Hello!" };
MessageBox.Show(typeof(Foo).GetProperty("Bar").GetValue(a,null) as string);
You need to use reflection. As an aside - note that reflection is slow(er), can lead to errors at runtime, doesn't respond to refactoring tools, etc. so you may want to rethink how you're doing things; eg., a Dictionary<string, string> seems like it'd be easier to manage.
For reflection, you'll need to get (a) the type since it seems you are referincing > 1 class, and then (b) the property. Something like:
var lookupKey = "Foo.Bar";
var typeName = lookupKey.Substring(0, lookupKey.LastIndexOf("."));
var propName = lookupKey.Substring(lookupKey.LastIndexOf(".") + 1);
var typeInfo = Type.GetType(typeName, true);
var propInfo = typeInfo.GetProperty(propName);
return propInfo.GetGetMethod().Invoke(null, null);

Store object string reference

I think this question was asked many times in C# but my problem is maybe more solvable.
I have an object value as a string : myobject.value and I want to store this value in a queue (or anything else) to access it later. Is it possible?
I read a lot of posts saying that it is not possible to store a ref to a string.
I don't see any solution to store a ref to my string value myobject.value and change it later.
Any Ideas ?
If you want to store a reference to a string that people can see and share the changes of you will need to wrap it in a class:
public class Wrapper<T>
{
public T Item { get; set; }
}
Then people use this instead of a string:
class MyClass
{
public Wrapped<string> SharedString { get; set; }
}
var c1 = new MyClass();
var c2 = new MyClass();
var s = new Wrapped<string> { Item = "Hello" };
c1.SharedString = s;
c2.SharedString = s;
c1.SharedString.Item = "World";
Console.Writeline(c2.SharedString.Item);
Even though strings are reference types, they are immutable so changes need to the "copied" around. Sharing is this way doesn't change the immutability, it just centrally holds one copy of a string that everyone is looking at via their reference to Wrapped<string>.
You can take the Wrapped<T> class further and give it implicit cast support to and from T, for a little syntactic sugar:
public static implicit operator T(Wrapped<T> wrapper)
{
return wrapper.Item;
}
public static implicit operator Wrapped<T>(T item)
{
return new Wrapped<T> { Item = item };
}
Wrapped<int> i = 2;
int j = i;
// Careful, this is a re-assignment of s, not a change of s.Item.
Wrapped<string> s = "Hello";
If I understand you right, and myobject.value is a string, than you can certainly store a collection representing those values
List<string> strLst = new List<string>();
strLst.Add(`myobject.value`);
No, you can't store a reference as a string, nor should you have to, but you can make a string(or xml) that represents all the information about your object, if you really need to.

How do I compare FieldInfo's values of instances?

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myClass instance1 = new myClass();
myClass instance2 = new myClass();
FieldInfo[] fields = typeof(myClass).GetFields();
foreach (FieldInfo field in fields) if (field.GetValue(instance2) == field.GetValue(instance1)) Text = "Yes";
}
}
class myClass
{
public bool b = false;
public int i = 2;
}
Never returns "Yes".
EDIT: Without knowing beforehand what the types will be. So I can't have: (bool)field.GetValue(instance1).
You're using ==, which will be comparing the boxed values for any field where the type is a value type. Each time a value is boxed, it will create a new object, so == will never work like that. Use object.Equals instead:
foreach (FieldInfo field in fields)
{
if (object.Equals(field.GetValue(instance2), field.GetValue(instance1))
{
Text = "Yes";
}
}
(Using the static method here means it'll work even if the values are null.)
you are comparing the address of the two objects returned by FieldInfo.GetValue and since those addresses in memory are different, the == is never true.
try replacing the if with this:
if (field.GetValue(instance2).Equals(field.GetValue(instance1)))
Because field.GetValue(instance1) returns a "boxed" (object) version of the value, hence calling == you are only comparing two different references.
Try instead calling:
field.GetValue(instance2).Equals(field.GetValue(instance1))

Categories

Resources