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);
Related
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"
var sample = new
{
Time = DateTime.Now,
Name = "Hello"
};
Trace.TraceInformation("{0}", sample);
outputs as
ProcessInvocation86.exe Information: 0 : { Time = 04.11.2012 22:07:52,
Name = Hello }
I'd like different formatting in my application. Is there a way to change the implementation of ToString() for anonymous objects in C#? Maybe some static field per AppDomain or something?
No, you can't do this - ToString, Equals, and GetHashCode have default implementation provided by framework. To override this functionality you should inherit from your anonymous type, which is impossible.
Use String.Format to get desired output.
As far as im aware, there is no way to override the default ToString behaviour.
Might be worthwhile looking at some of the posts from Eric Lippert about anonymous types: http://blogs.msdn.com/b/ericlippert/archive/tags/anonymous+types/
Probably best to create a simple class for this purpose:
e.g.
public class MyClass
{
public DateTime Time { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format("Time = {0}. Name = {1}.", Time, Name);
}
}
I know, some guys will actually punch me for such a solution and I agree, that you shouldn't use it in production. If you have specific functionality for some bunch of data - this should definitely go to separate class. But for minor issues, you can use a little of reflection like this to write some custom formatter (I repeat, I'm not suggesting to use it in production ):
private string FormatProperties<T> (T obj)
{
string result = "";
var type = typeof(T);
foreach (var prop in type.GetProperties())
{
result += string.Format("{0}:{1}\r\n", prop.Name, prop.GetValue(obj));
}
return result;
}
Then the call
var anon = new {Name = "Ilya", Surname = "Ivanov"};
Console.WriteLine (FormatProperties(anon));
Will result in printed
Name:Ilya
Surname:Ivanov
And then you can cache types for performance benefits and get into another types of troubles.
this isn't exactly ideal.. but you could create an extension method that takes a function that does the formatting.
Following example formatted for LinqPad
EXAMPLE
void Main()
{
var sample = new
{
Time = DateTime.Now,
Name = "Hello",
};
sample.ToAnonString(()=>sample.Name).Dump();
}
public static class ovs{
public static string ToAnonString(this object o,Func<string> exp){
return exp();
}
}
is it possible to have a public method that returns multiple values and then later call that method only retrieving the value that you want?
public static string Values()
{
string length = DAL.Util.getlength();
string Name = DAL.Util.getName(ddlID.SelectedValue);
return length + Name;
}
now I know if I were to call this method just by saying
string a = Values();
it would return the concatenated string of both length and Name, but is there anyway to call just a specific variable from that method even if it were 10 variables long?
Thanks for any advice and help you can provide.
It sounds like you should actually be returning a reference to an object which contains the various different bits of state, instead of returning a single string. Then the caller can decide which bits of state they're really interested in, and retrieve those properties directly.
You could return an object that contains all the values you require.
E.G.
public class MyClass
{
public string Length { get; set; };
public string Name { get; set; };
}
Then you can return this object from your function:
public static MyClass Values()
{
MyClass myClass = new MyClass();
MyClass.Length = DAL.Util.getlength();
MyClass.Name = DAL.Util.getName(ddlID.SelectedValue);
return MyClass;
}
Then you can get whatever properties you require:
MyClass myClass = Values();
string name = myClass.Name;
Sounds like what you actually want is a struct (or a class)
public struct MyStruct
{
public string length
public string name
}
public static MyStruct Values()
{
MyStruct result;
result.name = DAL.Util.getName(ddlID.SelectedValue);
result.length = DAL.Util.getlength();
return (result);
}
Then you can look at the different elements of the struct as you like.
MyStruct data = Values();
Console.WriteLine(data.name);
Console.WriteLine(data.length);
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..
I have a set of custom data types that can be used to manipulate basic blocks of data. For example:
MyTypeA Foo = new MyTypeA();
Foo.ParseString(InputString);
if (Foo.Value > 4) return;
Some of these types define read-only properties that describe aspects of the types (for example a name, bit size, etc.).
In my custom framework I want to be able to provide these types to the user for use in their applications but I also want to give the user a list of the available types which they could easily bind to a combobox. My current approach:
public static class DataTypes
{
static ReadOnlyCollection<MyDataType> AvailableTypes;
static DataTypes()
{
List<MyDataType> Types = new List<MyDataType>();
Types.Add(new MyTypeA());
Types.Add(new MyTypeB());
AvailableTypes = new ReadOnlyCollection<MyDataType>(Types);
}
}
What concerns me about this is that the user might obtain a type from the AvailableTypes list (by selecting a combobox item for example) and then use that reference directly rather than creating a clone of the type and using their own reference.
How can I make the list of available types read only so that it doesn't allow any writing or changes to the type instances, forcing the user to create their own clone?
Alternatively is there a better way of providing a list of available types?
Thanks, Andy
Make your custom Type class immutable, same as System.Type and you dont have to worry. A end user can fetch all the data it wants but he can not modify the object in any way.
EDIT: Example of immutable class
Take the following class for instance:
public class ImmutablePerson
{
private readonly string name; //readonly ensures the field can only be set in the object's constructor(s).
private readonly int age;
public ImmutablePerson(string name, int age)
{
this.name = name;
this.age = age;
}
public int Age { get { return this.age; } } //no setter
public string Name { get { return this.name; } }
public ImmutablePerson GrowUp(int years)
{
return new ImmutablePerson(this.name, this.age + years); //does not modify object state, it returns a new object with the new state.
}
}
ImmutablePerson is an immutable class. Once created there is no way a consumer can modify it in any way. Notice that the GrowUp(int years) method does not modify the state of the object at all, it just returns a new instance of ImmutablePerson with the new values.
I hope this helps you understand immutable objects a little better and how they can help you in your particular case.
To get around the problems you've mentioned, you could create a wrapper around your instances, and have the wrapper provide the functionality you require.
For example:
public class TypeDescriptor
{
private MyDataType _dataType;
public TypeDescriptor(MyDataType dataType)
{
_dataType = dataType;
}
public override string ToString()
{
return _dataType.ToString();
}
}
You class would then look something like:
public static class DataTypes
{
public static ReadOnlyCollection<TypeDescriptor> AvailableTypes;
static DataTypes()
{
List<TypeDescriptor> Types = new List<TypeDescriptor>();
Types.Add(new TypeDescriptor(new MyTypeA()));
Types.Add(new TypeDescriptor(new MyTypeB()));
AvailableTypes = new ReadOnlyCollection<TypeDescriptor>(Types);
}
}
Binding to the list and relying on the ToString() will now result in your data types ToString being called.
Create a list of types rather than a list of instances. e.g.
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB()));
etc.
To answer the comment on binding to a drop down list:
MyDropDown.Datasource = Type.Select(t => t.Name);
MyDropDown.DataBind();
This will not use the custom property of your classes but it will give you the simple calss name without all the other guff e.g. MyTypeA
A collection cannot "inject" type modifiers into its members. The collection you have declared is readonly. If you want MyDataType to be readonly you must declare that way.
Somthing like :
EDIT extended class to have a parse method
public class MyDataType
{
private MyDataType()
{
...
}
internal static MyDataType Parse(string someString)
{
MyDataType newOne = new MyDataType();
newOne.Value = ... //int.Parse(someString); ?
}
public int Value { get; private set; }
}
If the collection stays generic there is no readonly constraint.
You would use it like this, following your example.
MyTypeA foo = MyTypeA.Parse(inputString);
if (foo.Value > 4) return;
You probably shouldn't store instances of your types in the list. Instead you can store types. These can be used to create instances:
public static class DataTypes
{
static ReadOnlyCollection<Type> AvailableTypes;
static DataTypes()
{
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB));
AvailableTypes = new ReadOnlyCollection<MyDataType>(Type);
}
}
You can use Activator.CreateInstance to create a concrete instance:
Object myType = Activator.CreateInstance(AvailableTypes[0]);
Unless your types share a common base type you cannot downcast the result and an Object isn't that useful.
Also the use of the term type in your code makes my example a bit confusing as I suggest you store the types of something called type.
You could consider creating and attribute that you then can apply to MyTypeA, MyTypeB etc. Then you can build the AvailableTypes using reflection and the list will always be up to date with your code. E.g. if you add MyTypeC and use the attribute it will automatically be added to the list.
You can also add a display string property to the attribute and use that for display in the combo box. If you want to do that you should store a small object combining the type and the display string in AvailableTypes.
Here is an example. Using generic words like type and data can be confusing so to pick a random name I just use foo. Obviously you should use a more descriptive name.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
sealed class FooAttribute : Attribute {
public FooAttribute(String displayName) {
DisplayName = displayName;
}
public String DisplayName { get; private set; }
}
You can decorate you classes using this attribute:
[Foo("Type A")]
class MyTypeA { ... }
[Foo("Type B")]
class MyTypeB { ... }
For the combobox you want a list of factory objects with a nice ToString implementation (this class can be improved by adding some error handling which I have left out to save space):
class FooFactory {
readonly Type type;
public FooFactory(Type type) {
this.type = type;
DisplayName = ((FooAttribute) Attribute.GetCustomAttribute(
type,
typeof(FooAttribute))
).DisplayName;
}
public String DisplayName { get; private set; }
public Object CreateFoo() {
return Activator.CreateInstance(this.type);
}
public override String ToString() {
return DisplayName;
}
}
Returning Object from CreateFoo isn't very useful but that is a separate issue.
You can build this list at run-time:
var factories = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => Attribute.IsDefined(t, typeof(FooAttribute)))
.Select(t => new FooFactory(t));
I'm not exactly sure of what you want but should something like this be ok ?
public static class DataTypes
{
static Dictionary<string,Type> AvailableTypes
= new Dictionary<string,Type>()
{
{ "MyTypeA", MyTypeA },
{ "MyTypeB", MyTypeB },
...
};
}
That is actually return types instead of sample instances of theses types. Thus you would be sure that only new instances would be created by the user of your class.
Then in the calling code :
MyTypeA a = Activator.CreateInstance(DataTypes.AvailableTypes["MyTypeA"]);