Sample Class:
public abstract class SomeBase
{
protected int _x = 100;
public abstract int X { get; }
protected int _y = 200;
public abstract int Y { get; }
}
public class SomeBody : SomeBase
{
public override int X { get { return _x + 10; } }
public override int Y { get { return _y + 20; } }
private int _z = 300;
public int Z { get { return _z + 30; } }
}
public class SomeOne : SomeBase
{
public override int X { get { return _x - 10; } }
public override int Y { get { return _y - 20; } }
private int _a = 300;
public int A { get { return _a - 30; } }
}
Object to ExpandoObject Method:
public static ExpandoObject ToExpandoObject<T>(this T target)
{
var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.Converters.Add(new StringEnumConverter());
var json = JsonConvert.SerializeObject(target, Formatting.Indented, jsonSerializerSettings);
var expandoObject = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());
return expandoObject;
}
Convert ExpandoObject to abstract object:
//someBase
//X = 110, Y = 220, Z = 330
SomeBase someBase = new SomeBody();
//someOne
//X = 90, Y = 180, A = 270
dynamic someOne = new SomeOne().ToExpandoObject();
Mapper.Initialize(cfg =>
{
cfg.CreateMap<SomeBase, SomeBase>();
});
//I want
//someBase
//X = 90, Y = 180, A = 270
Mapper.Map<ExpandoObject, SomeBase>(someOne, someBase);
But error occurs.
Instances of abstract classes can not be created
How can we handle this problem?
AutoMapper version is 6.02
*Please consider using Google translator because English is immature.
UPDATE:
I know about abstract.
I just want to know if AutoMapper can do the following:
SomeBody someBody = new SomeBody();
//someBase
//X = 110, Y = 220, Z = 330
SomeBase someBase = someBody;
SomeOne someOne = new SomeOne();
//someBase
//X = 90, Y = 180, A = 270
someBase = someOne;
UPDATE Again...
TestClass
public class TestClass
{
public int IntValue { get; set; }
public SomeBase SomeBase { get; set; }
}
My final goal is :
var testClass = new TestClass();
testClass.IntValue = 10;
testClass.SomeBase = new SomeBody();
dynamic expandoObject = testClass.ToExpandoObject();
expandoObject.SomeBase = new SomeOne().ToExpandoObject();
Mapper.Initialize(cfg =>
{
cfg.CreateMap<TestClass, TestClass>();
});
///Mapping the expandoObject object that changed the property to the testClass object again
///My expectation is that the type of SomeBase Property in testClass is SomeOne.
Mapper.Map<ExpandoObject, TestClass>(expandoObject, testClass);
Thank you very much for helping me with insufficient English and insufficient explanation.
My solution
var testClass = new TestClass();
testClass.IntValue = 10;
testClass.SomeBase = new SomeBody();
dynamic expandoObject = testClass.ToExpandoObject();
expandoObject.SomeBase = new SomeOne().ToExpandoObject();
Mapper.Initialize(cfg =>
{
cfg.CreateMap<ExpandoObject, SomeBase>().ConvertUsing(new SomeBaseConverter());
cfg.CreateMap<FirstItem, FirstItem>();
});
Mapper.Map<ExpandoObject, TestClass>(expandoObject, testClass);
Debug.WriteLine(testClass.SomeBase.GetType().ToString());
///"Sample.Common.Models.SomeOne"
SomeBaseConverter:
public class SomeBaseConverter : ITypeConverter<object, SomeBase>
{
public SomeBase Convert(dynamic source, SomeBase destination, ResolutionContext context)
{
var dictionary = source as IDictionary<string, object>;
if (dictionary.ContainsKey("Z"))
{
var someBody = new SomeBody();
var config = new MapperConfiguration(cfg => cfg.CreateMap<ExpandoObject, SomeBody>());
config.CreateMapper().Map(source, someBody);
destination = someBody;
}
else
{
var someOne = new SomeOne();
var config = new MapperConfiguration(cfg => cfg.CreateMap<ExpandoObject, SomeOne>());
config.CreateMapper().Map(source, someOne);
destination = someOne;
}
return destination;
}
}
See the MSDN article re abstract classes.
The important part for you is:
An abstract class cannot be instantiated.
You need to map to one of the derived classes, or remove the abstract modifier from the base class.
AutoMapper is great if you have statically-typed objects. It handles polymorphism very well:
Mapper.CreateMap<SomeBase1, SomeBase2>()
.Include<SomeBody1, SomeBody2>()
.Include<SomeOne1, SomeOne2>();
Mapper.CreateMap<SomeBody1, SomeBody2>();
Mapper.CreateMap<SomeOne1, SomeOne2>();
// for a single object:
SomeBase1 source = GetDatum();
SomeBase2 = Mapper.Map<SomeBase1, SomeBase2>();
// for an IEnumerable:
IEnumerable<SomeBase1> source = GetData();
IEnumerable<SomeBase2> = Mapper.Map<IEnumerable<SomeBase1>, IEnumerable<SomeBase2>>(source);
But you're using ExpandoObject, so it's more difficult. If you can differentiate which class you need by the data in the ExpandoObject, you could try something like this:
Mapper.CreateMap<ExpandoObject, SomeBase>()
.ConstructUsing((ExpandoObject input) => {
if (input.X == 5)
{
return new SomeOne();
}
else
{
return new SomeBody();
}
});
and then the code you were using before Mapper.Map<Expandoobject, SomeBase>(...) will work. Otherwise, you could specifically tell it which type to map to: Mapper.DynamicMap<SomeBody>(someOne);
Related
I've seen ways to list all variables in a certain class, but is there a way to set their values?
I want a method I can call, and it can reset all variables' values to false / 0 , I know I can manually set those to false / 0, but any change to their values would mess up everything, and I'm just seeing if there's anything more dynamic / easy way that this could be done ?
Currently I'm doing the following:
// These are just some of the vars that are here.
Error = false;
double GUM = 0, MUM = 0;
decimal Mass = 0, GAcc = 0, Fg = 0, FµsRes = 0, FµkRes = 0, Fµs = FµsNS.Value, Fµk = FµkNS.Value;
As others have mentioned, you could use Reflection to set all the class fields to their default values:
using System;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.Error = true;
myClass.GUM = 1;
myClass.MUM = 2;
myClass.Mass = 3.5m;
myClass.GAcc = 4.5m;
myClass.Fg = 5.5m;
ResetFields(myClass);
// All fields are reseted
}
public static void ResetFields(object source)
{
foreach (var fieldInfo in source.GetType().GetFields() )
{
fieldInfo.SetValue(source, GetDefault(fieldInfo.FieldType) );
}
}
public static object GetDefault(Type type)
{
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
}
public class MyClass
{
public bool Error = false;
public double GUM = 0, MUM = 0;
public decimal Mass = 0, GAcc = 0, Fg = 0;
//etc etc
}
}
A better approach however, is to create a class to only hold the values and re-create it when needed:
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
myClass.Variables = new MyVariables();
myClass.Variables.Error = true;
myClass.Variables.GUM = 1;
myClass.Variables.MUM = 2;
myClass.Variables.Mass = 3.5m;
myClass.Variables.GAcc = 4.5m;
myClass.Variables.Fg = 5.5m;
myClass.Variables = new MyVariables();
// All fields are reseted
}
}
public class MyVariables
{
public bool Error = false;
public double GUM = 0, MUM = 0;
public decimal Mass = 0, GAcc = 0, Fg = 0;
}
public class MyClass
{
public MyVariables Variables;
// etc etc
public int Xyz
{
get { return Variables.GUM + Variables.MUM; } // Use calculated properties
}
}
}
The GetDefault method is shown in this answer.
I have an enum with 30 items in it. Each item has a corresponding function with the same name. I would like to be able to call the function by referencing the enum at a certain position.
So if the value at enum[0] = Foo, I would like to be able to call Foo(string bar) by using something like enum(0)("foobar")
In the end the point is I am running each function as a task like so:
enum Test { AA, BB, CC, DD ....}
tasks[0] = Task.Run(() => { prices[0] = AA("a string"); });
tasks[1] = Task.Run(() => { prices[1] = BB("a string"); });
tasks[2] = Task.Run(() => { prices[2] = CC("a string"); });
//for 30 tasks
What I would like to do is something along the lines of:
enum Test { AA, BB, CC, DD ....}
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() => { prices[i] = (Test)i("a string"); });
}
Task.WaitAll(tasks.ToArray());
Is this something that is even possible?
EDIT:
The enum relates to controls on a form so i have an array of textboxs, label and a array of prices that is populated with the results of the functions:
enum Dealers { Dealer1, Dealer2 ... Dealer29, Dealer30 };
static int noOfDealers = Enum.GetNames(typeof(Dealers)).Length;
decimal[] prices = new decimal[noOfDealers];
TextBox[] textBox = new TextBox[noOfDealers];
Label[] boxes = new Label[noOfDealers];
for (int i = 0; i < noOfDealers; i++)
{
textBox[i] = Controls.Find("txt" + (Dealers)i, true)[0] as TextBox;
boxes[i] = Controls.Find("box" + (Dealers)i, true)[0] as Label;
prices[i] = 0;
}
//RUN 30 TASKS TO POPULATE THE PRICES ARRAY
for (int i = 0; i < noOfDealers; i++)
{
textBox[i].Text = "£" + prices[i].ToString();
}
//LOOP THROUGH PRICES ARRAY AND FIND CHEAPEST PRICE, THEN COLOUR THE LABEL BACKGROUND GREEN FOR THE TEXT BOX WITH THE NAME AT ENUM VALUE WHATEVER I IS
I guess i am just trying to make my code as concise as possible, there is the potential for the amount of tasks to double and didn't want to end up with 60 lines to populate the tasks array
I would create dictionary and map enum to actions:
Dictionary<Test, Func<string,double>> actions = new Dictionary<Test, Func<string,double>>()
{
{Test.AA, (x) => { return 5;}},
{Test.BB, (x) => { return 15; }},
}; //x is your string
var res = actions[Test.AA]("hello");
I would strongly suggest using a built in construct - like an extension method and a simple switch:
public static int GetPriceWithString(this Test test, string str)
{
switch (test)
{
case Test.AA:
break;
case Test.BB:
break;
case Test.CC:
break;
case Test.DD:
break;
default:
throw new ArgumentOutOfRangeException(nameof(test), test, null);
}
}
then your loop looks almost the same:
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() =>
{
prices[i] = ((Test)i).GetPriceWithString("a string");
});
}
What you want to do is possible with reflection, which can be a powerful tool - but ideally should only be used as a last resort, as it will hide what could be compile time errors, and cause less code readability.
Using a simple switch like this makes your code self-documented, so when you come back to this in a month you can quickly remember what the intention was.
How about using an array of delegates:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
private static int AA(string a) { return 0; }
private static int BB(string a) { return 1; }
private static int CC(string a) { return 2; }
private static Func<string, int>[] functions = new Func<string, int>[] { AA, BB, CC };
private static int[] prices = new int[functions.Length];
private static Task[] tasks = new Task[functions.Length];
static void Main(string[] args)
{
for (int i = 0; i < functions.Length; ++i)
tasks[i] = Task.Run(() => { prices[i] = functions[i]("a string"); });
Task.WaitAll(tasks);
}
}
}
An eg. speaks a lot more than words.
I used it in a winform so the this refers to win form.
I have assumed all your methods are public , have same signature & return the same type.
enum MyName { AA,BB,CC};
//Call this in one of your methods
string [] strVal= Enum.GetNames(typeof(MyName));
int x = CallFunction(strVal[0], "A");
int y = CallFunction(strVal[1], "h");
int z = CallFunction(strVal[1], "C");
//End Call this in one of your methods
int CallFunction(string strName,string strValue)
{
return Convert.ToInt32(this.GetType().InvokeMember(strName, BindingFlags.Public | BindingFlags.InvokeMethod|BindingFlags.Instance, null, this, new object[] { strValue }));
}
public int AA(string s)
{
return 1;
}
public int BB(string s)
{
return 2;
}
public int CC(string s)
{
return 3;
}
Another solution. I hope somebody will consider it as overkill :)
Create abstract class DealerBase.
public abstract class DealerBase
{
public string Name { get; }
public decimal Price { get; set; }
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
}
Then create classes for every dealers you have and implement own logic for UpdatePrice method.
public class Dealer1 : DealerBase
{
public Dealer1() : base("DealerOne") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerOneCalculationMethod();
}
}
public class Dealer2 : DealerBase
{
public Dealer2() : base("DealerTwo") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerTwoCalculationMethod();
}
}
And so on..
Then you just create collection of dealers which can be easily iterated
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
}
foreach(var dealer in dealers)
{
dealer.UpdatePrice();
}
You can loop dealers and generate textboxes, labels in the winforms.
But I suggest to use DataGridView where code will be tiny clearer.
First implement INotifyPropertyChanged interface in the base class DealerBase
public abstract class DealerBase : INotifyPropertyChanged
{
public string Name { get; }
protected decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
if (Equals(_Price, value)) return;
_Price = value;
// next method will inform DataGridView about changes
// and update value there too
RaisePropertyChanged();
}
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
The in the Form you can create BindingList<DealerViewModelBase> and set it to DataGridView.DataSource
public class YourForm: Form
{
public YourForm()
{
InitializeComponent();
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
};
var bindSource = new BindingList<DealerBase>(dealers);
dataGridView.DataSource = bindSource;
}
// Add button which update prices for all dealers
private void ButtonUpdatePrices_Click(object sender, EventArgs e)
{
var dealers = (BindingList<DealerBase>)dataGridView.DataSource;
foreach (var dealer in dealers)
{
dealer.UpdatePrice();
// Because we call `RaisePropertyChanged` in
// setter of Price - prices will be automatically
// updated in DataGridView
}
}
}
Idea of this approach you put different logic of different dealers in the separated class which. Because all dealer classes will inherit from same abstract class you can add different dealers to the collection.
You already have hardcoded enums and correspondent method which you try to link together. This approach make using of dealers collection little bid easy
EDIT: Updated to include actual code.
I am having an issue with some custom generic interfaces and I am not entirely sure what to do. The error I'm getting is:
Cannot convert from Map to IMap<ICell>
That error pops up when I try to pass Map as a parameter to a method that accepts IMap<ICell>. I have pasted sample code below. Just to be clear, FieldOfView doesn't use anything that hasn't been defined in ICell or IMap.
public class Map : IMap<Cell>
{
private FieldOfView _fieldOfView;
public int Width { get; }
public int Height { get; }
public Map(int width, int height)
{
Width = width;
Height = height;
_fieldOfView = new FieldOfView(this as IMap<ICell>);
_fieldOfView = new FieldOfView((IMap<ICell>)this);
}
public IEnumerable<Cell> GetAllCells()
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
yield return GetCell(x, y);
}
}
}
public Cell GetCell(int x, int y)
{
return new Cell(x, y);
}
public void Copy(IMap<Cell> sourceMap)
{
// ...
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var cell in GetAllCells())
{
sb.Append(cell.ToString());
}
return sb.ToString();
}
}
public interface IMap<T> where T : ICell
{
int Width { get; }
int Height { get; }
IEnumerable<T> GetAllCells();
T GetCell(int x, int y);
void Copy(IMap<T> sourceMap);
}
public class Cell : ICell
{
public int X { get; }
public int Y { get; }
public Cell(int x, int y)
{
X = x;
Y = Y;
}
public override string ToString()
{
return "overloaded";
}
}
public interface ICell
{
int X { get; }
int Y { get; }
}
public class FieldOfView
{
private readonly IMap<ICell> _map;
public FieldOfView(IMap<ICell> map)
{
_map = map;
}
public void DoStuff()
{
foreach (var cell in _map.GetAllCells())
{
// ...
}
}
}
This is similar to this stack overflow question, but a little different. I tried implementing an interface IMap as well as IMap<T> : IMap where T : ICell, but am having issues with that as well.
Lastly, I'm not sure if this is solvable with co/contravariance, but I am using C#3.0 so that is out of the picture for me (unless switching versions is the only way).
I think it would be fine with an implicit / direct cast?
_fieldOfView = new FieldOfView(this as IMap<ICell>); // or
_fieldOfView = new FieldOfView((IMap<ICell>)this);
But if there is a better way, I would like to do that. Resharper does throw me a warning when I cast Map to IMap<ICell> saying:
Suspicious cast: there is no type in the solution which is inherited from both Map and IMap<ICell>.
EDIT2: Look's like neither of the casts worked. I've decided instead to make Map be derived from IMap and just create the Cell objects where needed in the code.
Thanks #Rob and #MK87 for your help!
No, IMap<Cell> is not the same as IMap<ICell>, so this line:
_fieldOfView = new FieldOfView(this as IMap<ICell>);
will always pass null as parameter.
Yes, this is definitely solvable with variance.
For example, you can have:
IEnumerable<object> list = new List<string>();
since list is IEnumerable<outT>, that means that every IEnumerable<TT> with TT that derives from T is a valid value for list. So the List doesn't have to be of object, it can be of any derived type.
But because you can't use variance, we need another hack.
Possible solution: instead of deriving Map from IMap<Cell>, derive it from IMap<ICell>. You'll have only to correct some points, for example the return type of GetCell() must become ICell instead of Cell. Is it feasable for you?
Here is the code snippet from my LinqPad:
public class Elephant{
public int Size;
public Elephant()
{
Size = 1;
}
}
public struct Ant{
public int Size;
}
private T[] Transform2AnotherType<T>(Elephant[] elephantList)
where T:new()
{
dynamic tArray = new T[elephantList.Length];
for (int i = 0; i < elephantList.Length; i++)
{
tArray[i] = new T();
tArray[i].Size = 100;
//tArray[i].Dump();
}
return tArray;
}
void Main()
{
var elephantList = new Elephant[2];
var elephant1 = new Elephant();
var elephant2 = new Elephant();
elephantList[0] = elephant1;
elephantList[1] = elephant2;
elephantList.Dump();
var r = Transform2AnotherType<Ant>(elephantList);
r.Dump();
}
I want to change one object array of known type,Elephant,to another object array of type T. T is not a class,but limited to struct which
provided by the already existed API.And every instance of type T shares some common property,says Size,but also has their own particular property which
I have omitted in my example code.So I put dynamic keyword inside the Transform2AnotherType<T>.
And I could not even to use Dump to make sure if the assignment has made effect,thus will throw RuntimeBinderException.
My question is: how to correctly make the assignment in such a struct array and return it back properly?
I suggest change your code like this:
public class Elephant
{
public Elephant()
{
Size = 1;
}
public int Size { get; set; }
}
public struct Ant
{
public int Size { get; set; }
}
private static T[] Transform2AnotherType<T>(Elephant[] elephantList)
where T : new()
{
T[] tArray = new T[elephantList.Length];
for (int i = 0; i < elephantList.Length; i++)
{
dynamic arrayElement = new T();
arrayElement.Size = 100;
tArray[i] = arrayElement;
//tArray[i].Dump();
}
return tArray;
}
static void Main()
{
var elephantList = new Elephant[2];
var elephant1 = new Elephant();
var elephant2 = new Elephant();
elephantList[0] = elephant1;
elephantList[1] = elephant2;
//elephantList.Dump();
var r = Transform2AnotherType<Ant>(elephantList);
//r.Dump();
}
I have this same code on two places:
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
x = amount[0].Trim();
y = amount[1].Trim();
}
else
{
x = "1";
y = amountUnit.Trim();
}
//
unit = textInBrackets.Replace(amountUnit, "");
name = "";
for (int z = 0; z < i; z++)
{
name += someArray[z];
name += " ";
}
name = name.Trim();
The exact code is repeated twice. How to fix it? If i extract it in a new method, I'll have a lot of ref input parameters. Is there another way?
If it's not possible, just the part untill the comments?
Like:
public struct Parameters
{
public int X {get; set;}
public int Y {get; set;}
}
public Parameters ExtractParameters(string amountUnit)
{
var parameters = new Parameters();
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
parameters.X = int.Parse(amount[0].Trim());
parameters.Y = int.Parse(amount[1].Trim());
}
else
{
parameters.X = 1;
parameters.Y = int.Parse(amountUnit.Trim());
}
return parameters;
}
Usage:
var parameters = ExtractParameters(amountUnit);
var x = parameters.X;
var y = parameters.Y;
You can also make it an extension method on string.
And of course you best add some exception handling too.
The code seems to have two, separate blocks, logically.
One that deals with x and y - the other with name. These should probably be separate methods.
Now, you can create a type (class or structure) that encapsulates x and y, meaning that you only need to pass in one parameter. Instead of passing it by ref you can simply return it and in the caller replace what you passed in.
Combine your code and your data into a class ;-)
public class Point
{
public Point(string amountUnit)
{
if (amountUnit == null)
{
throw new ArgumentNullException("amountUnit");
}
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
this.X = amount[0].Trim();
this.Y = amount[1].Trim();
}
else
{
this.X = "1";
this.Y = amountUnit.Trim();
}
}
string X { get; private set; }
string Y { get; private set; }
}
If you don't need anything very dynamic, how about splitting it into two methods, and doing something as simple as this:
public static string GetX(string amountUnit)
{
return amountUnit.ToLower().Contains("x") ?
amountUnit.Split('x')[0].Trim() :
"1";
}
public static string GetY(string amountUnit)
{
return amountUnit.ToLower().Contains("x") ?
amountUnit.Split('x')[1].Trim() :
amountUnit.Trim();
}