i have a class with some properties like this:
public class Car
{
public long No { get; set; }
public string Name { get; set; }
public int Door { get; set; }
public Color Color { get; set; }
public int MaxSpeed { get; set; }
public int Price { get; set; }
}
(this class is an example, my real class is very bigger than it.)
In my program, I need to get difference properties of this class from db(not all properties each time). For example in one case I need name and color of some cars, and in other case I need name and door and price.
I want to create one method that support all difference conditions. I know that i could create it using ‘params’ and ‘enum’, but I am research about best way to do it. Thanks
You can just query the propertie when it is called.
public int Value{
get{
int myValue = getValue();
return myValue;
}
}
Try do this way:
public object[] GetProperties(int state)
{
object[] temp;
switch(state)
{
case(0):
{
temp=new object[]{Name,Color};
}break;
case(1):
{
temp=new object[]{Name,door};
}
}
}
After that, you know , what need return your function, and it's easy parse return result!
Related
In C#, is it possible to read a class tree path in a string and access programmatically a value, given an instance of that class ?
For example:
public class LogGeometricModel
{
public double SmallEndDiameter { get; set; }
public double LargeEndDiameter { get; set; }
public class Log
{
public Guid Id { get; set; }
public LogGeometricModel GeometricModel { get; set; }
}
public class Solution
{
public DateTime TimeStamp { get; set; }
public double Price { get; set; }
public Log RotatedLog { get; set; }
}
The strings could be something like this (a path in the class tree):
SmallEndDiameter = "Solution/RotatedLog/GeometricModel/SmallEndDiameter"
LargeEndDiameter = "Solution/RotatedLog/GeometricModel/LargeEndDiameter"
Price = "Solution/Price"
Id = "Solution/Log/Id"
By reading those strings, I would like to access the actual values of SmallEndDiameter, LargeEndDiameter, Price and Id.
Absolutely possible yes.
public static object GetValue(object instance, string path)
{
object currentObject = instance;
foreach (string propertyName in path.Split('/'))
{
currentObject = currentObject
.GetType()
.GetProperty(propertyName)
.GetValue(currentObject, null);
}
return currentObject;
}
You don't need to include 'Solution' in the string. This obviously lacks error handling, which if you are parsing a string like this, you will want.
The sub class isn't derived from the main class, I'm just trying to differentiate them.
Even as I type this I can see it being impossible but I have some classes:
public class TransferServiceInformation {
public int ProviderId { get; set; }
public string PrePurchaseOverride { get; set; }
public bool PrePurchaseOverrideEnabled { get; set; }
}
and
public class TransferServiceProviderInformation {
public int ProviderId { get; set; }
public string PrePurchaseInfo { get; set; }
And I want it so that if I ever try to access myTransferServiceInformation.PrePurchaseOverride and PrePurchaseOverrideEnabled == false it should return PrePurchaseInfo from the TransferServiceProviderInformation with the same ID.
Is something like that even possible?
I'm just having a thought that a getter that requires a TransferServiceProviderInformation passed as an argument might work, and throw an exception if the IDs don't match. Is that the only solution? The thing is, I'd rather not have to dig through all the (thousands of lines of) code to change all the places were I (or someone else) has called this property.
This is just an idea:
Make a static list with instances inside your class and auto-fill it with using the constructor. Then you can check this list from outside for instances with the same id.
public class TransferServiceInformation
{
public int ProviderId { get; set; }
private string prePurchaseOverride;
public string PrePurchaseOverride
{
get
{
if(!PrePurchaseOverrideEnabled)
{
// Get instances from the other class where providerID matches
var instance = TransferServiceProviderInformation.Instances.Where(i => i.ProviderId == this.ProviderId).FirstOrDefault();
if(instance != null)
return (instance).PrePurchaseInfo;
}
return null; // If no match found
}
set
{
prePurchaseOverride = value;
}
}
private bool prePurchaseOverrideEnabled;
public bool PrePurchaseOverrideEnabled { get; set; }
}
public class TransferServiceProviderInformation
{
// Store your instances static
public static List<TransferServiceProviderInformation> Instances { get; set; }
public TransferServiceProviderInformation()
{
// Add every new instance to the list
Instances.Add(this);
}
public int ProviderId { get; set; }
public string PrePurchaseInfo { get; set; }
}
To-do's:
If an instance gets disposed, delete it from the list of instances.
First of all I'm new to C#.
The error I get is:
Additional information: Unable to cast object of type 'UserGUI.MyItems' to type 'CommonBookLib.AbstractItem'.
They are 2 different classes:
public class MyItems
{
public string ItemName { get; set; }
public int CopyNumber { get; set; }
public int Guid { get; set; }
public DateTime? TimePrinted { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public bool? BestSeller { get; set; }
}
and
public class AbstractItem : IPropsDetails
{
public int CopyNumber { get; }
public string ItemName { get; }
public DateTime Time { get; }
public int Guid { get; }
public AbstractItem(int copyNumber, string itemName, DateTime time, int guid)
{
this.CopyNumber = copyNumber;
this.ItemName = itemName;
this.Time = time;
this.Guid = guid;
}
}
It happens when I do:
AbstractItem myItemsList = (AbstractItem)LibraryList.SelectedItem;
logicManager.Remove(myItemsList);
Well, as you can see, I have MyItems which are responsible for the DataBindings in my GUI and AbstractItem which responsible for implementing an addition operation to where my data is saved.
Since I did not managed my code well I got into this situation and I really do not want to change MyItems (delete and recode AbstractItem).
How can I Convert the two?
By the way, I know AbstractItem has only 4 properties while MyItems has more.
However, I have children with the exact same properties of AbstractItem.
Any help would be appreciated. Thanks in advance!
Remove fields from the MyItems class that are also present in AbstractItem, and then have MyItems derive from it instead.
You'll have to add a constructor to MyItems that passes the required values to the base constructor, or add an empty constructor to the base class.
public class MyItems : AbstractItem
{
public MyItems(int copyNumber, string itemName, DateTime time, int guid)
:base(copyNumber, itemName, time, guid)
{
}
public DateTime? TimePrinted { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public bool? BestSeller { get; set; }
}
You can make MyItems inherit AbstractItem, or make a method that handle the conversion between them.
You seem to need a mapper more than a cast. Look at AutoMapper or write your own routine as suggested by habibhassani. Also, Grant's answer is very good.
But your question was about casting so here I show how you can implement a casting operator so that your cast would work. This is not a technique you should reach for lightly. It puts a dependency on AbstractItem directly in MyItems and it is not the most discoverable pattern for maintainers of your code.
public class MyItems
{
public string ItemName { get; set; }
public int CopyNumber { get; set; }
public int Guid { get; set; }
public DateTime? TimePrinted { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public bool? BestSeller { get; set; }
public static explicit operator AbstractItem(MyItems myitems)
{
return new AbstractItem(myitems.CopyNumber, myitems.ItemName, myitems.TimePrinted, myitems.Guid);
}
}
A couple more observances. Naming your class AbstractItem is confusing, it implies that it is actually abstract but it is not.
Guid is a poor name for a property because it is already a Type. You have something named Guid that is an int - confusing.
I have an application following the MVVM pattern, that has to serialize XML files. As some of the XML attributes are nested, I've created nested classes inside my Model, like this:
public class OPER_FILE
{
public UNB unb { get; set; }
public OPER oper { get; set; } //nested class, level 1
public OPER_FILE()
{
unb = new UNB();
oper = new OPER();
}
}
public class OPER
{
public UNH unh { get; set; } //these are all nested classes, level 2
public UVT uvt { get; set; }
public VIN vin { get; set; }
public OPER()
{
unh = new UNH();
uvt = new UVT();
}
}
#region "nested classes"
public class UNB
{
public string unb { get; set; }
public string unb_2 { get; set; }
}
public class UNH
{
public string unh { get; set; }
public string unh_2 { get; set; }
}
public class UVT
{
public string uvt { get; set; }
public string uvt_1 { get; set; }
public string uvt_2 { get; set; }
}
public class VIN
{
public string vin { get; set; }
public string vin_1 { get; set; }
public string vin_2 { get; set; }
public string vin_3 { get; set; }
public string vin_4 { get; set; }
}
#endregion
The attributes of the nested classes are all strings, because this simplifies the XML serialization for now (I'm still in the conception phase).
In my corresponding ViewModel, I've simply created a property for the nested class inside the model, so I can access all of the nested properties with just referring to this nested class from the ViewModel.
public class OPERViewModel : IViewModelBase
{
private OPER_FILE Model;
public UNB unb
{
get
{ return Model.unb;}
set
{ Model.unb = value; }
}
public OPER oper
{
get
{ return Model.oper; } //this is the tricky part, by now I'm just referring to the nested class as a property of the model
set
{ Model.oper = value; }
}
public OPERViewModel()
{ Model = new OPER_FILE(); }
}
The question is, however, that I want to display some of the properties not as strings but as boolean values using checkboxes on the UI.
Saying I want to display Model.oper.vin.vin_1 as boolean (where the ViewModel should manage the conversion from string to bool in the getter of its own property reflection of Model.oper.vin.vin_1), how would I do that?
Would I really have to implement every nested property from a nested class as an own property of the ViewModel (like stated below) to gain control over the way it will be returned to the UI?
//ViewModel-implementation with type-conversion of a property from a nested class of the model
//this would get bind to the UI instead of Model.oper.vin.vin_1
public bool vin_1
{
get
{
if (Model.oper.vin.vin_1 == "1")
{ return true; }
else
{ return false; }
}
set
{
if (value)
{ Model.oper.vin.vin_1 = "1"; }
else
{ Model.oper.vin.vin_1 = "0"; }
}
}
I hope there is a better solution out there...
Edit:
What I forgot to mention before, there're not only strings that have to be displayed as booleans, also DateTime-values that should be displayed as a DatePicker-control, integer-values that I would like to have as NumberPickers and so on.
The xml-file, on the other hand, will be consumed by an interface with some pretty fixed regulations that i need to match, such a dynamically leading zeros on both integer- and float-values, special date formats and commas instead of dots as decimal separators. So sticking with the string-values inside the object to serialize is a good way of maintaining control over how the values would get actually parsed inside the xml-file.
I'll try and experiment with some different converters, as #BrandlyDOTNet reommended, but are still curious about how this could be solved in another way.
There's a different solution out there, namely that you can use a converter to define the translation between your strings and a bool.
Something like:
public class StringToBoolConverter : IValueConverter
{
public object Convert(...)
{
return value.ToString() != "0";
}
public object ConvertBack(...)
{
bool boolVal = (bool)value;
return boolVal ? "1" : "0";
}
}
Usage:
<CheckBox IsChecked={Binding SomeProp, Converter={StaticResource StringToBoolConverter}"/>
But to answer your deeper question, no, the framework will not just convert the string "1" into a bool. Moreover, you can strongly type your object that is being serialized, so none of this is actually necessary.
I have a number of classes that are all related conceptually, but some more-so at the details level than others. For example, these three classes have nearly identical properties (although member functions will vary):
public class RelatedA : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedB : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedC : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
public int Special { get; set; }
}
There are a couple of other classes that are conceptually related to the above 3, but can be a bit different implementation-wise:
public class RelatedD : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
}
public class RelatedE : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
public bool IsNew { get; set; }
}
Instances of these can be created by a factory based on some sort of "type" enumerated value. The problem is that later on when these objects are being used (in a business layer, for example), there could be a lot of code like this:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
if (theObject is RelatedC)
{
RelatedC cObject = theObject as RelatedC;
specialVal = cObject.Special;
}
else if (theObject is RelatedD)
{
RelatedD dObject = theObject as RelatedD;
statementVal = dObject.Statement;
}
else if (theObject is RelatedE)
{
RelatedE eObject = theObject as RelatedE;
statementVal = eObject.Statement;
isNewVal = eObject.IsNew;
}
This could be repeated in many places. Is there a better approach to the design that I should be using (there's got to be)?
You could try and factor the differences into seperate classes that are then provided so for example:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
RelatedTypeHelper theHelper=TheFactory.CreateHelper(theObject);
theHelper.DoSpecialThing(theObject);
Now you won't have to have all the if else blocks, and if you add a new type which requires new handling, you just whip up a new helper implement the required pieces and you should be good to go. The helper should help document this process.
I would also question why a single method would have such a different implementation for specialVal and StatementVal could be your sample, but It makes me curious what your really doing here. can you simplify things back taking a step back and questioning the point of these being included in this specific hierarchy.