I'm working on a project at the moment that will make use of a certain kind of object (which we will call "Machine" in this case. This type of object has parameters, methods etc. pp. and I want to use its methods.
In this special case I will have a text field that allows the user to alter a certain property of an object of my own class, lets call it "Name" for simplicity. This property "Name" can be changed by typing a Name into a text field that is available to the user. Validating this text field will call a method from "Machine" for a certain object of that class which can be chosen from a ComboBox somewhere else on that page.
As these objects are created dynamicly, I have no idea how many of these objects there are and how they are called in particular, I only know that they exist.
How would you approach this kind of situation? Is there any way that you can basicly say "treat it as XY and use its methods as if you were sure it was of a certain type"? (Like a cast?)
Or would you solve this problem in other ways?
Use dynamic.
dynamic d = machine as dynamic;
d.Name = userInput;
That said, if you can force these object to implement an interface with the properties you care about your code will be faster and safer.
You can benefit from using dictionary collection :
class MyClass
{
public string Prop1 { get; private set; }
public int Prop2 { get; private set; }
public double Prop3 { get; private set; }
public Dictionary<string, Action<object>> Updater { get; private set; }
public MyClass()
{
Updater = new Dictionary<string, Action<object>>()
{
{"Prop1", o => Prop1 = o as string},
{"Prop2", o => Prop2 = (int)o},
{"Prop3", o => Prop3 = (double)o},
};
}
}
class Class27
{
static void Main()
{
Dictionary<string, MyClass> instances = new Dictionary<string, MyClass>();
instances.Add("First", new MyClass());
instances["First"].Updater["Prop1"]("hello");
instances["First"].Updater["Prop2"](10);
Console.WriteLine(instances["First"].Prop1);
Console.WriteLine(instances["First"].Prop2);
}
}
Output: hello, 10
Related
I'm trying to convert some anonymous type back to its original strong type class.
I have some legacy code (which I cannot touch) which create an anonymous class:
public class Cat : FooId
{
public int Id { get; set; }
public string Name { get; set; }
}
var result = new
{
Id = Mapper.Map<TFooId>(someCat)
};
NOTE: I've tried to make this fake class and interface similar to my code.
This then gives me:
result.GetType().ToString() : <>f__AnonymousType1``1[MyProject.Cat]
From here, I'm not sure how to convert this back to a MyProject.Cat instance?
I've tried (and fails):
(MyProject.Cat)result
(dynamic)result
but both fail. The dynamic doesn't throw an error ... but I can't access any properties in it.
C# is a statically typed language, and those two types are not in any way related to one another. Unless you're able to modify the code which defines those types, the way you'd convert from one to the other would be to create a new instance of the target type and populate it from the source object.
For example:
var resultCat = new Cat { Id = result.Id };
Edit: From comments it looks like it may be possible that the Id property on the result object may be an instance of Cat or some other object? You're going to need to do some debugging to find out what your types are.
But the overall concept doesn't really change. If you have an instance of Cat in your results then you can use that instance. If you don't then in order to create one you'd need to create a new instance and populate it with the data you have. Even if two types are intuitively or semantically similar, they are different types.
It's true what David said with regard to the fact that C# is a statically-typed language and that the new instance should be populated from the source the way he suggested.
However, there are work-arounds (though less performant) for that, such as reflection.
Consider you have a console app where you have defined ObjectExtensions as follows:
public static class ObjectExtensions
{
public static TOut Map<TOut>(this object #in)
where TOut : new()
{
TOut #out = new TOut();
if (#in?.GetType() is Type tin)
{
Type tout = typeof(TOut);
foreach ((PropertyInfo pout, PropertyInfo pin) in tout.GetProperties().Join(tin.GetProperties(), pi => pi.Name, pi => pi.Name, (pout, pin) => (pout, pin)))
{
pout.SetValue(#out, pin.GetValue(#in));
}
}
return #out;
}
}
And Class1 as follows:
public class Class1
{
public string A { get; set; } = "A";
public string B { get; set; } = "B";
public string C { get; set; } = "C";
public override string ToString()
{
return $"{{A={A}, B={B}, C={C}}}";
}
}
You will be able to map your anonymous type back to its original strongly-typed class like this:
Console.WriteLine(new { A = "Anonymous A", B = "Anonymous B", C = "Anonymous C" }.Map<Class1>());
Therefore the bloc above should show the following output:
{A=Anonymous A, B=Anonymous B, C=Anonymous C}
In this case, of course, I have assumed that Class1 (Cat in your example) must have a public parameterless constructor. That may not always be the case. There are more sophisticated scenarios of course that might involve other techniques for creating the object such as cloning or dependency injection. Just saying that the idea of yours is possible.
I have an application where i have say 10 objects of different types. I wish to have them in same list and iterate through them on many occasions. I cant push them into one list because they are of different types. So i created an interface and created a property that all objects share. Now i have the list of objects and type of the list is the "interface". When i iterate through the object, i can't access the specific properties of the object because the compiler will only know at runtime what object it is. So if i try to code Object_A.Name, visual studio will show error because it doesn't know they type of object. I can obviously do an if else or something similar to find the type of object and cast it, but i want to know of there is a better way, or if this whole approach of having an interface is wrong and if i should have begun in a different direction.
In the code below, i want to get the Devname, which i can't because its not part of the interface, but belongs to every object. I could make it part of the interface, but every now and then i may need to get a specific property. hence wanting to know if there is a way to do it.
foreach (ICommonDeviceInterface device in Form1.deviceList)
{
if (device.DevName.Equals(partnername))
{
return device.Port[portNo].PortRef;
}
}
One way you could do this is by using reflection to try to get the property value of a named property from an object, using a helper method like:
public static object GetPropValue(object src, string propName)
{
return src?.GetType().GetProperty(propName)?.GetValue(src, null);
}
Credit for above code goes to: Get property value from string using reflection in C#
This requires no checking types or casting, it just returns the value of the property, or null if it doesn't contain the property.
In use it might look like:
private static void Main()
{
// Add three different types, which all implement the same interface, to our list
var devices = new List<ICommonDeviceInterface>
{
new DeviceA {DevName = "CompanyA", Id = 1},
new DeviceB {DevName = "CompanyB", Id = 2},
new DeviceC {Id = 3},
};
var partnerName = "CompanyB";
foreach (var device in devices)
{
// Try to get the "DevName" property for this object
var devName = GetPropValue(device, "DevName");
// See if the devName matches the partner name
if (partnerName.Equals(devName))
{
Console.WriteLine($"Found a match with Id: {device.Id}");
}
}
}
Classes used for the sample above:
interface ICommonDeviceInterface
{
int Id { get; set; }
}
class DeviceA : ICommonDeviceInterface
{
public int Id { get; set; }
public string DevName { get; set; }
}
class DeviceB : ICommonDeviceInterface
{
public int Id { get; set; }
public string DevName { get; set; }
}
class DeviceC : ICommonDeviceInterface
{
public int Id { get; set; }
}
Use "as" and "is" to know what type of interface
public class A : ICommonDeviceInterface
{
public int AMember;
}
public class B :ICommonDeviceInterface
{
public int BMember;
}
foreach (ICommonDeviceInterface device in Form1.deviceList)
{
if(device is A)
{
A a = device as A;
a.AMember = 100;
}
else if(device is B)
{
B b = device as B;
b.BMember = 123;
}
}
private List<T> newList;
public List<T> NewList
{
get{return newList;}
set{newList = value;}
}
I want to create something like this, but this is won't work. it's just an example to demonstrate my goal as it's pretty common creating proprties for string and int and even T but I've never seen a List property
Is it even possible do such a thing, creating a property for type List ?
EDIT
I have a normal class that has normal properties (string properties, int properties, etc) but I have this property that stores user options, So on the presentation layer I had to convert them into a string so I could be able to store them in the Object. Now is it possible to have a property of type List to store the multivalues in a better and clean way, instead of converting information into one string and then split it and again join it! Thanks Again =D
EDIT2
private List<KeyValuePair<string, string>> _settings;
public List<KeyValuePair<string, string>> MySettings
{
get { return _settings; }
set { _settings = value; }
}
I used the exact code you posted but the property still won't appear in the object's instance, so I tried adding code in the get and set (I wonder why you left them empty or does it means something?) and also added a private variable in the class but still it doesn't appear in the properties of the object's instance!
I hope you could provide the exact code to implement this property and a simple code that assigns or retrieves from/to an instance of this class object
It's the first time to even hear about this KeyValuePair and all the tutorials are pretty simple and not for my case, sorry!
The Last Edit: After a lot of researching and the help of Mark Avenius I found the perfect answer. hope everyone can benefit from this.
NOW! HOW TO CREATE A PROPERTY FOR A LIST :
The Options Class
Public Class Options
{
private string id;
private int option;
public int ID
{
get { return id; }
set { id= value; }
}
public string Option
{
get { return option; }
set { option = value; }
}
}
The Users Class
public class Users
{
private int userId;
private string pass;
private List<Options> userOptions = new List<Options>();
public int ID
{
get { return userId; }
set { user = userId; }
}
public string Pass
{
get { return pass; }
set { pass = value; }
}
public List<Options> OptionsList
{
get { return userOptions; }
set { userOptions = value; }
}
}
The Presentation Layer
Users newUser = new Users ();
Options userOption = new Options ();
userOption.ID = int.Parse(txtBxID.Text);
userOption.Option = txtBxOption.Text;
Item.Options.Add(userOption);
T must be defined within the scope in which you are working. Therefore, what you have posted will work if your class is generic on T:
public class MyClass<T>
{
private List<T> newList;
public List<T> NewList
{
get{return newList;}
set{newList = value;}
}
}
Otherwise, you have to use a defined type.
EDIT: Per #lKashef's request, following is how to have a List property:
private List<int> newList;
public List<int> NewList
{
get{return newList;}
set{newList = value;}
}
This can go within a non-generic class.
Edit 2:
In response to your second question (in your edit), I would not recommend using a list for this type of data handling (if I am understanding you correctly). I would put the user settings in their own class (or struct, if you wish) and have a property of this type on your original class:
public class UserSettings
{
string FirstName { get; set; }
string LastName { get; set; }
// etc.
}
public class MyClass
{
string MyClassProperty1 { get; set; }
// etc.
UserSettings MySettings { get; set; }
}
This way, you have named properties that you can reference instead of an arbitrary index in a list. For example, you can reference MySettings.FirstName as opposed to MySettingsList[0].
Let me know if you have any further questions.
EDIT 3:
For the question in the comments, your property would be like this:
public class MyClass
{
public List<KeyValuePair<string, string>> MySettings { get; set; }
}
EDIT 4: Based on the question's edit 2, following is how I would use this:
public class MyClass
{
// note that this type of property declaration is called an "Automatic Property" and
// it means the same thing as you had written (the private backing variable is used behind the scenes, but you don't see it)
public List<KeyValuePair<string, string> MySettings { get; set; }
}
public class MyConsumingClass
{
public void MyMethod
{
MyClass myClass = new MyClass();
myClass.MySettings = new List<KeyValuePair<string, string>>();
myClass.MySettings.Add(new KeyValuePair<string, string>("SomeKeyValue", "SomeValue"));
// etc.
}
}
You mentioned that "the property still won't appear in the object's instance," and I am not sure what you mean. Does this property not appear in IntelliSense? Are you sure that you have created an instance of MyClass (like myClass.MySettings above), or are you trying to access it like a static property (like MyClass.MySettings)?
Simple and effective alternative:
public class ClassName
{
public List<dynamic> MyProperty { get; set; }
}
or
public class ClassName
{
public List<object> MyProperty { get; set; }
}
For differences see this post: List<Object> vs List<dynamic>
public class MyClass<T>
{
private List<T> list;
public List<T> MyList { get { return list; } set { list = value; } }
}
Then you can do something like
MyClass<int> instance1 = new MyClass<int>();
List<int> integers = instance1.MyList;
MyClass<Person> instance2 = new MyClass<Person>();
IEnumerable<Person> persons = instance2.MyList;
You could do this but the T generic parameter needs to be declared at the containing class:
public class Foo<T>
{
public List<T> NewList { get; set; }
}
It's possible to have a property of type List<T> but your class needs to be passed the T too.
public class ClassName<T>
{
public List<T> MyProperty { get; set; }
}
Either specify the type of T, or if you want to make it generic, you'll need to make the parent class generic.
public class MyClass<T>
{
etc
How can I use reflection to create a generic List with a custom class (List<CustomClass>)? I need to be able to add values and use
propertyInfo.SetValue(..., ..., ...) to store it. Would I be better off storing these List<>'s as some other data structure?
Edit:
I should have specified that the object is more like this, but Marc Gravell's answer works still.
class Foo
{
public List<string> Bar { get; set; }
}
class Foo
{
public string Bar { get; set; }
}
class Program
{
static void Main()
{
Type type = typeof(Foo); // possibly from a string
IList list = (IList) Activator.CreateInstance(
typeof(List<>).MakeGenericType(type));
object obj = Activator.CreateInstance(type);
type.GetProperty("Bar").SetValue(obj, "abc", null);
list.Add(obj);
}
}
Here's an example of taking the List<> type and turning it into List<string>.
var list = typeof(List<>).MakeGenericType(typeof(string));
This is probably a simple question. Suppose I have a object called Users and it contains a lot of protected variables.
Inside that Users class I have a method that creates a temporary Users object, does something with it, and if successful, transfers all the variables from the temp Users object into the one I have.
Is there some fast way to transfer all the variables from one Users object into another Users object without doing this using C#?
this.FirstName = temp.FirstName;
this.LastName = temp.LastName;
........75 variables later......
this.FavoriteColor = temp.FavoriteColor
A better approach is to implement the IClonable interface. But you'll find it doesn't save you a lot of work.
You should check out cloning in C#.
Deep cloning objects
I think serializing and then deserializing an object will create a new object instance. This should be identical to the former object.
A better solution might be to move whatever this method is outside of your class, and then just assign the temp user object to your main user object reference like so:
_User = tmpUser;
sparing you the 75 lines of code. Whenever I have a class creating an instance of itself inside one of its own methods, I always like to blink a couple of times and make sure I really need to be doing that.
There's always the reflection option. Something substantially similar to this:
public static void Copy(object source, object target)
{
foreach (System.Reflection.PropertyInfo pi in source.GetType().GetProperties())
{
System.Reflection.PropertyInfo tpi = target.GetType().GetProperty(pi.Name);
if (tpi != null && tpi.PropertyType.IsAssignableFrom(pi.PropertyType))
{
tpi.SetValue(target, pi.GetValue(source, null), null);
}
}
}
Doesn't require the source and the target to have any relation what-so-ever, just a name and an IsAssignable check. It has the interesting side effects if you're using reference types anywhere, but for the kind of situation you just described, this isn't a bad option to explore.
class sourceTester
{
public bool Hello { get; set; }
public string World { get; set; }
public int Foo { get; set; }
public List<object> Bar { get; set; }
}
class targetTester
{
public int Hello {get; set;}
public string World { get; set; }
public double Foo { get; set; }
public List<object> Bar { get; set; }
}
static void Main(string[] args)
{
sourceTester src = new sourceTester {
Hello = true,
World = "Testing",
Foo = 123,
Bar = new List<object>()
};
targetTester tgt = new targetTester();
Copy(src, tgt);
//Immediate Window shows the following:
//tgt.Hello
//0
//tgt.World
//"Testing"
//tgt.Foo
//0.0
//tgt.Bar
//Count = 0
//src.Bar.GetHashCode()
//59129387
//tgt.Bar.GetHashCode()
//59129387
}