Store object string reference - c#

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.

Related

Is it possible to make a variable that can be an array or a non-array?

I want to be able to do something like
public string[]|string stringsOrSingleString;
I want to create a variable that can be an array or a non-array of a specific type (a string in the example).
Example usage
I want to be able to do stringsOrSingleString = "bla" or stringsOrSingleString = new string[] { "bla" };
Do I need a custom class to do this? Preferably, I don't want to use a custom class, but if necessary then ok.
I should be able to tell later on if the value assigned was an array or non-array, using typeof or is, or something.
The whole reason for this ordeal is that I have a javascript API(that I didn't create), and I am trying to make a C# api that follows the JS api/syntax as close as possible.
Is this possible?
May be you want something like this?
public class Item<T>
{
public T Value => this.Values.Length > 0 ? this.Values[0] : default(T);
public T[] Values { get; set; }
}
The class has an array of values and a single value. There are some implementations like this, for example, when you select files with OpenFileDialog: you have a list of files (for MultiSelect case) and also a single SelectedFile. My answer is focused with this in mind. If you need another thing, give more information.
UPDATE
You can update previous class in this way:
public class Item<T>
{
public T Value => this.Values.Length > 0 ? this.Values[0] : default(T);
public T[] Values { get; set; }
public T this[int index] => this.Values[index];
public static implicit operator Item<T>(T value)
{
return new Item<T> { Values = new[] { value } };
}
public static implicit operator Item<T>(List<T> values)
{
return new Item<T> { Values = values.ToArray() };
}
public static implicit operator Item<T>(T[] values)
{
return new Item<T> { Values = values };
}
}
Example usage:
Item<string> item = "Item1";
string text = item.Value;
string sameText = item[0];
Item<string> items = new[] { "Item1", "Item2" };
string[] texts = item.Values;
string item1 = item[0];
string item2 = item[1];
You can create an instance using a simple object or an array. You can access to the first value using Value property and to all items using Values. Or use the indexer property to access to any item.
In C# you need to know the type of the variable. It's difficult work in the same form of JavaScript. They are very different languages.

Get and set value from bindinglist<T> with coordinates c#

I'm having trouble getting and setting the values of an item in a bindinglist with coordinates when the type vary.
For example, let's say I have three classes:
public class Client{
public string Name{ get; set; }
}
public class Debt{
public string AccountType{ get; set; }
public int DebtValue { get; set; }
}
public class Accounts{
public string Owner{ get; set; }
public int AccountNumber { get; set; }
public bool IsChekingAccount { get; set; }
}
and then, three bindinglists (imagine they are populated):
public BindingList<Client> listOne;
public BindingList<Debt> listTwo;
public BindingList<Accounts> listThree;
I'm trying to create an extension method that returns an Object with the value requested, or sets the value if it is provided.
public static Object GetValueByCoordinates(this IBindingList list, int x, int y) { /*some magic*/ }
public static Object SetValueByCoordinates(this IBindingList list, int x, int y, Object value) { /*some other magic*/ }
So, for instance, I need to be able to set the value of the item (2,3) in the listThree, and the value (1,1) in listTwo:
listThree.SetValueByCoordinates(2,3,false);
listThree.SetValueByCoordinates(1,1,"My self");
or get the value (1,1) and (2,2) from listOne and listTwo:
string result = listOne.GetValueByCoordinates(1,1).ToString();
intresult = Convert.ToInt32(listOne.GetValueByCoordinates(1,1));
How would you achieve such behavior? i was thinking of using reflection, but I know little to nothing about it.
please note that the methods MUST be called that way, so using something like this must be avoided
public static Object GetValueByCoordinates<T>(this BindingList<T> list, int x, int y) { /*some magic*/ }
Any help will be appreciated.
As mentioned, I am very skeptical that the approach you're asking for help with is likely to be the best or most appropriate way to address whatever the broader issue you're trying to solve is. It can be done (and without very much difficulty), but the resulting code is difficult to maintain, error-prone, and not very readable (which leads to the first two problems).
That said, there are lots of different ways to implement the specific behavior you're asking for. And even if this is not the best way to solve your current problem, the basic techniques are useful to know for other types of problems. With that in mind, here are two of the most obvious ways you might address your problem.
Manually configure a mapping from indexes to getters and setters:
IMHO this is the most preferable way. Not because it's elegant or easy to extend, but specifically because it's not either of those things. Requiring code maintainers to explicitly create the data structure elements to support each type and property that you want to handle will discourage a proliferation of this technique for other related problems, and even for the current problem. It could even encourage someone to spend a little more time thinking about the broader problem so as to find a better strategy.
This approach does have the advantage that it is reasonably performant. Because the code is generated at compile time, the only real overhead is the boxing that occurs for value types. There's some casting but for the reference types that overhead should be practically unmeasurable, and even the boxing overhead may not show up on a profile, depending on how intensively this code might be used.
This particular solution looks like this:
static class ManualIndexedProperty
{
public static void SetValueByCoordinates(this IBindingList list, int x, int y, object value)
{
object o = list[x];
_typeToSetter[o.GetType()][y](o, value);
}
public static object GetValueByCoordinates(this IBindingList list, int x, int y)
{
object o = list[x];
return _typeToGetter[o.GetType()][y](o);
}
private static readonly Dictionary<Type, Func<object, object>[]> _typeToGetter =
new Dictionary<Type, Func<object, object>[]>()
{
{
typeof(Client),
new Func<object, object>[]
{
o => ((Client)o).Name
}
},
{
typeof(Debt),
new Func<object, object>[]
{
o => ((Debt)o).AccountType,
o => ((Debt)o).DebtValue,
}
},
{
typeof(Accounts),
new Func<object, object>[]
{
o => ((Accounts)o).Owner,
o => ((Accounts)o).AccountNumber,
o => ((Accounts)o).IsChekingAccount,
}
},
};
private static readonly Dictionary<Type, Action<object, object>[]> _typeToSetter =
new Dictionary<Type, Action<object, object>[]>()
{
{
typeof(Client),
new Action<object, object>[]
{
(o1, o2) => ((Client)o1).Name = (string)o2
}
},
{
typeof(Debt),
new Action<object, object>[]
{
(o1, o2) => ((Debt)o1).AccountType = (string)o2,
(o1, o2) => ((Debt)o1).DebtValue = (int)o2,
}
},
{
typeof(Accounts),
new Action<object, object>[]
{
(o1, o2) => ((Accounts)o1).Owner = (string)o2,
(o1, o2) => ((Accounts)o1).AccountNumber = (int)o2,
(o1, o2) => ((Accounts)o1).IsChekingAccount = (bool)o2,
}
},
};
}
Two dictionaries are declared, one each for setting and getting property values. The dictionaries map the element object's type to an array of delegate instances to perform the actual work. Each delegate instance references an anonymous method which has been hand-coded to perform the necessary operation.
One major advantage to this approach is that it is explicit and obvious what index corresponds to what property for each type.
This approach will be tedious and time-consuming to set up if you are dealing with any significant number of types and/or properties. But IMHO that's a good thing. As I noted above, hopefully the pain of this approach can help convince someone to abandon the idea of accessing the properties by index altogether. :)
If this kind of tedium is unacceptable and yet you still insist on the indexed-property-access approach, then you can in fact use reflection as an alternative…
Use reflection to access the properties:
This technique is more dynamic. Once implemented, it works for any type object without modification, and does not require additional work to support new types.
One major disadvantage is that in order to produce consistent, predictable results, it sorts the properties by name. This ensures that changes in the C# compiler and/or CLR won't break the code, but it means you can't add or remove properties from a type without updating the code that is accessing those properties by index.
In my demo usage code (see further below), I address this maintenance issue by declaring enum types that provide int values for property names. This would be a good way to help reduce the maintenance overhead if the code is actually referring to the properties with literal index values.
However, it's possible your scenario involves dynamically accessing the property values by index, e.g. in a serialization scenario or similar. In that case, you will also need to add something that can remap or otherwise deal with changes in the index values should properties be added or removed to the types.
Frankly, either way this issue of the types indexes changing is one big reason I'd strongly recommend against this indexed access to properties in the first place. But again, if you insist…
static class ReflectionIndexedProperty
{
public static void SetValueByCoordinates(this IBindingList list, int x, int y, object value)
{
object o = list[x];
GetProperty(o, y).SetValue(o, value);
}
public static object GetValueByCoordinates(this IBindingList list, int x, int y)
{
object o = list[x];
return GetProperty(o, y).GetValue(o);
}
private static PropertyInfo GetProperty(object o, int index)
{
Type type = o.GetType();
PropertyInfo[] properties;
if (!_typeToProperty.TryGetValue(type, out properties))
{
properties = type.GetProperties();
Array.Sort(properties, (p1, p2) => string.Compare(p1.Name, p2.Name, StringComparison.OrdinalIgnoreCase));
_typeToProperty[type] = properties;
}
return properties[index];
}
private static readonly Dictionary<Type, PropertyInfo[]> _typeToProperty = new Dictionary<Type, PropertyInfo[]>();
}
In this version, the code retrieves the array of PropertyInfo objects for a given type, sorts that array by name, retrieves the appropriate PropertyInfo object for the given index, and then uses that PropertyInfo object to set or get the property value, as appropriate.
Reflection incurs a significant run-time performance overhead. This particular implementation mitigates some of that overhead by caching the sorted arrays of PropertyInfo objects. That way, they only need to be created once, the first time the code has to handle an object of the given type.
Demo code:
As I mentioned, to make it easier to compare the two approaches without having to go to each method call and hand-change an integer literal used for the call, I created some simple enum types to represent the property indexes. I also wrote some code to initialize some lists that could be tested.
Note: one very important thing to point out is that in your question you were not very consistent about how you were indexing the properties. In my code example, I have chose to stick with a 0-based index (consistent with the natural indexing used in C# arrays and other collections). You can of course use a different base (e.g. 1-based indexing), but you will need to make sure you are entirely consistent throughout the code (including subtracting 1 from the passed-in index when actually indexing an array).
My demo code looks like this:
class Program
{
static void Main(string[] args)
{
BindingList<Client> listOne = new BindingList<Client>()
{
new Client { Name = "ClientName1" },
new Client { Name = "ClientName2" },
new Client { Name = "ClientName3" },
};
BindingList<Debt> listTwo = new BindingList<Debt>()
{
new Debt { AccountType = "AccountType1", DebtValue = 29 },
new Debt { AccountType = "AccountType2", DebtValue = 31 },
new Debt { AccountType = "AccountType3", DebtValue = 37 },
};
BindingList<Accounts> listThree = new BindingList<Accounts>()
{
new Accounts { Owner = "Owner1", AccountNumber = 17, IsChekingAccount = false },
new Accounts { Owner = "Owner2", AccountNumber = 19, IsChekingAccount = true },
new Accounts { Owner = "Owner3", AccountNumber = 23, IsChekingAccount = true },
};
LogList(listThree);
listThree.SetValueByCoordinates(2, (int)AccountsProperty.IsChekingAccount, false);
listThree.SetValueByCoordinates(1, (int)AccountsProperty.Owner, "My self");
LogList(listThree);
string result1 = (string)listOne.GetValueByCoordinates(0, (int)ClientProperty.Name);
int result2 = (int)listTwo.GetValueByCoordinates(1, (int)DebtProperty.DebtValue);
LogList(listOne);
LogList(listTwo);
Console.WriteLine("result1: " + result1);
Console.WriteLine("result2: " + result2);
}
static void LogList<T>(BindingList<T> list)
{
foreach (T t in list)
{
Console.WriteLine(t);
}
Console.WriteLine();
}
}
Note that I use simple casting to convert from object to the specific type, both with setting property values and getting them. This is a much better approach than e.g. calling ToString() or Convert.ToInt32(); you know exactly what the type is supposed to be, and it's either an actual instance of that type (for reference types) or a boxed instance (for value types), and either way a cast does exactly what you need.
I also added ToString() overrides to your example classes to make it easier to see the output:
public class Client
{
public string Name { get; set; }
public override string ToString()
{
return "{" + Name + "}";
}
}
public class Debt
{
public string AccountType { get; set; }
public int DebtValue { get; set; }
public override string ToString()
{
return "{" + AccountType + ", " + DebtValue + "}";
}
}
public class Accounts
{
public string Owner { get; set; }
public int AccountNumber { get; set; }
public bool IsChekingAccount { get; set; }
public override string ToString()
{
return "{" + Owner + ", " + AccountNumber + ", " + IsChekingAccount + "}";
}
}
Finally, here are the enum declarations used:
Manual indexing:
enum ClientProperty
{
Name = 0
}
enum DebtProperty
{
AccountType = 0,
DebtValue = 1
}
enum AccountsProperty
{
Owner = 0,
AccountNumber = 1,
IsChekingAccount = 2,
}
Reflection/sorted by name:
enum ClientProperty
{
Name = 0
}
enum DebtProperty
{
AccountType = 0,
DebtValue = 1
}
enum AccountsProperty
{
AccountNumber = 0,
IsChekingAccount = 1,
Owner = 2,
}
Of course, these could both have been the same values. That is, while you don't have control over the sort order, once the property names are given, the manual version could have declared the manually-written lambdas in sorted-by-name order so that the same indexes would have worked either way. It doesn't matter too much what you decide to do; it just has to be consistent.
Final thoughts…
Have I mentioned yet how strongly I would recommend against building any significant amount of code around this technique? It's not at all clear what your actual bigger-picture problem you're trying to solve is, but there are just a lot of different ways for this to go wrong, and it is likely to lead to lots of hard-to-find, time-consuming-to-fix bugs in the code.
In terms of performance, the above should not be too bad as long as you are not executing the code in a tight loop for huge numbers of objects and property values. The manual (first) example in particular should be relatively fast. It is possible to achieve the generalized design of the reflection-based approach with the minimal overhead of the manual approach by using the Expression type. That's a bit more complicated, but would have the advantage that you can generate expressions dynamically that wind up being effectively the compiled-code implementation of the manual approach.

How to pass string into collection by reference?

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..

c# copy constructor generator

I want to copy values from one object to another object. Something similar to pass by value but with assignment.
For example:
PushPin newValPushPin = oldPushPin; //I want to break the reference here.
I was told to write a copy constructor for this. But this class has a lot of properties, it will probably take an hour to write a copy constructor by hand.
Is there a better way to assign an object to another object by value?
If not, is there a copy constructor generator?
Note: ICloneable is not available in Silverlight.
If you can mark the object that is to be cloned as Serializable then you can use in-memory serialization to create a copy. Check the following code, it has the advantage that it will work on other kinds of objects as well and that you don't have to change your copy constructor or copy code each time an property is added, removed or changed:
class Program
{
static void Main(string[] args)
{
var foo = new Foo(10, "test", new Bar("Detail 1"), new Bar("Detail 2"));
var clonedFoo = foo.Clone();
Console.WriteLine("Id {0} Bar count {1}", clonedFoo.Id, clonedFoo.Bars.Count());
}
}
public static class ClonerExtensions
{
public static TObject Clone<TObject>(this TObject toClone)
{
var formatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
formatter.Serialize(memoryStream, toClone);
memoryStream.Position = 0;
return (TObject) formatter.Deserialize(memoryStream);
}
}
}
[Serializable]
public class Foo
{
public int Id { get; private set; }
public string Name { get; private set; }
public IEnumerable<Bar> Bars { get; private set; }
public Foo(int id, string name, params Bar[] bars)
{
Id = id;
Name = name;
Bars = bars;
}
}
[Serializable]
public class Bar
{
public string Detail { get; private set; }
public Bar(string detail)
{
Detail = detail;
}
}
There is a protected member called "MemberwiseClone", you can write this in your class...
public MyClass Clone(){
return (MyClass)this.MemberwiseClone();
}
then you can access..
MyClass newObject = oldObject.Clone();
The only way (that I'm aware of) to do this, and do it correctly, is to implement the copy yourself. Take for example:
public class FrobAndState
{
public Frob Frobber { get; set;}
public bool State { get; set; }
}
public class Frob
{
public List<int> Values { get; private set; }
public Frob(int[] values)
{
Values = new List<int>(values);
}
}
In this example you'd need to know how Frob was implemented, i.e. the fact that you need to call the constructor to create a copy of it as Values is read-only, to be able to make a copy of a given instance of FrobAndState.
Also - you couldn't just implement FrobAndState.Copy thusly:
public class FrobAndState
{
// ... Properties
public FrobAndState Copy()
{
var new = new FrobAndState();
new.State = this.State;
new.Frobber = this.Frobber;
}
}
Because both the instance of FrobAndState that you called .Copy() on, and the new instance would both have a reference to the same instance of Frobber.
In short, copying things is hard and any Copy implementation is difficult to get right.
C# does not have a copy constructor. There are different ways to tackle this. At the OOP level you could use inheritance or aggregation. AutoMapper might also be worth a try.
I want to copy values from one object
to another object. Something similiar
to pass by value but with assignment.
What do you mean by "with assignment"? If you mean that you want people to be able to say:
a = b;
And for you to define what = means, the only way you can do that in C# is if b is a different type to a and you've defined an implicit conversion (or more tenuously, if a stands for something of the form x.Y where Y is a property with a setter). You can't override = for a simple assignment between identical types in C#.
I was told to write a copy constructor
for this. But this class has alot of
properties, it will probably take an
hour to write a copy constructor by
hand.
If that's really true, then I would guess that you have a different problem. Your class is too big.
If you make your class Serializable you could Serialize it to a MemoryStream and Deserialize to a new instance.
If you want copy-on-assignment you should be using a struct instead of a class. But be careful, it is easy to make subtle mistakes. It is highly recommended that all stucts be immmutable to reduce the chance for error.
Though, this may not answer your question directly, but to add a cent; usually the term Clone is linked with shallow copy(referenced objects). To have a deep copy, I believe you will need to look into the some creational pattern(prototype?). The answer to this question might help.
You implement Justin Angel's method of cloning objects in Silverlight
using System;
using System.Reflection;
using System.Windows;
namespace JustinAngelNet.Silverlight.Framework
{
public static class SilverlightExtensions
{
public static T Clone<T>(T source)
{
T cloned = (T) Activator.CreateInstance(source.GetType());
foreach (PropertyInfo curPropInfo in source.GetType().GetProperties())
{
if (curPropInfo.GetGetMethod() != null
&& (curPropInfo.GetSetMethod() != null))
{
// Handle Non-indexer properties
if (curPropInfo.Name != "Item")
{
// get property from source
object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] {});
// clone if needed
if (getValue != null && getValue is DependencyObject)
getValue = Clone((DependencyObject) getValue);
// set property on cloned
if (getValue != null)
curPropInfo.GetSetMethod().Invoke(cloned, new object[] {getValue});
}
// handle indexer
else
{
// get count for indexer
int numberofItemInColleciton =
(int)
curPropInfo.ReflectedType.GetProperty("Count").GetGetMethod().Invoke(source, new object[] {});
// run on indexer
for (int i = 0; i < numberofItemInColleciton; i++)
{
// get item through Indexer
object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] {i});
// clone if needed
if (getValue != null && getValue is DependencyObject)
getValue = Clone((DependencyObject) getValue);
// add item to collection
curPropInfo.ReflectedType.GetMethod("Add").Invoke(cloned, new object[] {getValue});
}
}
}
}
return cloned;
}
}
}
Then you can do this
MyClass newObject = SilverlightExtensions.Clone(oldObject);

Variable number of results from a function

I have code similar to the following in many places:
var dbParams = db.ReadParams(memberID, product, GetSubscriptionFields());
Debug.Assert(dbParams.Count == 4);
_memberCode = dbParams[0];
_password = dbParams[1];
_userName = dbParams[2];
_reasonCode = dbParams[3];
ReadParams() returns an array of strings, the number of strings depending on the GetSubscriptionFields() function. I could use dbParams[] directly in my code, but I find it more helpful to give meaningful names to each of the values in the array. Is there a way I can get all the results directly, without going through the array?
I am looking for something like:
db.ReadParams(memberID, product, out _memberCode, out _password, out _userName, out _reasonCode);
or
Tuple<_memberCode, _password, _userName, _reasonCode> = db.ReadParams(memberID, product);
Of course, it has to be legal C# code :)
You are writing code in a highly object oriented language, so why don't you use objects?
Member m = db.ReadParams(memberID, product, GetSubscriptionFields());
and in your code you use
m.memberCode
m.password
m.username
m.reasonCode
Of course you don't have to make the values publicly accessible, you can make them only accessible via setter/getter methods, and by only having getters, you can avoid them from being altered after object creation.
Of course different calls to db.ReadParams should return different objects, e.g. you can create an abstract base class and inherit all possible results from db.ReadParams of it. Therefor you may have to encapsulate db.ReadParams into another method that finds out the right type of object to create:
ReadParamsResult rpr = myDb.ReadParamsAsObject(memberID, product, GetSubscriptionFields());
// Verify that the expected result object has been returned
Debug.Assert(rpr is Member);
// Downcast
Member m = (Member)rpr;
Why not use constants instead?
Then in your code you could have
dbParams[MEMBER_CODE]
dbParams[PASSWORD]
dbParams[USERNAME]
dbParams[REASON_CODE]
which meets your goal of meaningful names without changing the way the method works.
I think your Tuple idea is pretty good. You could define it like this:
public class Tuple<T1, T2, T3, T4>
{
public T1 Field1 { get; set; }
public T2 Field2 { get; set; }
public T3 Field3 { get; set; }
public T4 Field4 { get; set; }
}
You would probably want to define a few of those, with two and three properties. Unfortunately it doesn't help you naming the properties of the class. There really is no way to do that (at least not until C# 4.0, when you could use dynamic typing with an anonymous type.
Not really; since the number of arguments isn't fixed, there isn't really a better way of doing it. The problem with regular tuples is that you are still working positionally - just with ".Value0" instead of "[0]". And anonymous types can't be directly exposed in an API.
Of course, you could subsequently wrap the values in your own class with properties, and just do a projection:
return new Foo {MemberCode = arr[0], ...}
(where Foo is your class that represents whatever this result is, with named, typed properties)
Alternatively you could throw them into a dictionary, but this doesn't help the caller any more than an array does.
The only other option is something really grungy like accepting a params array of Action<string> that you use to assign each. I'll elaborate on the last just for fun - I don't suggest you do this:
static void Main()
{
string name = "";
int value = 0;
Foo("whatever",
x => { name = x; },
x => { value = int.Parse(x); });
}
// yucky; wash eyes after reading...
static void Foo(string query, params Action<string>[] actions)
{
string[] results = Bar(query); // the actual query
int len = actions.Length < results.Length ? actions.Length : results.Length;
for (int i = 0; i < len; i++)
{
actions[i](results[i]);
}
}
I also came up with this... I kinda like it most, but it's a personal preference, I understand it's definitely not the cleanest idea:
using System.Diagnostics;
public static class ArrayExtractor
{
public static void Extract<T1>(this object[] array, out T1 value1)
where T1 : class
{
Debug.Assert(array.Length >= 1);
value1 = array[0] as T1;
}
public static void Extract<T1, T2>(this object[] array, out T1 value1, out T2 value2)
where T1 : class
where T2 : class
{
Debug.Assert(array.Length >= 2);
value1 = array[0] as T1;
value2 = array[1] as T2;
}
}
Of course, I am extending this class up to 10 or 15 arguments.
Usage:
string fileName;
string contents;
ArrayExtractor.Extract(args, out fileName, out contents);
or even better
args.Extract(out fileName, out contents);
where args is, of course, an object array.

Categories

Resources