I know casting is not inherently bad practice, but is it bad in this situation?
I have the following class hierarchy, and the cast at the end.
public class A<T>
{
public A(string name, T value)
{
Name = name;
Value = value;
}
public string Name { get; }
public T Value { get; }
}
public class B : A<double>
{
public B(string name, double value, string expression)
: base(name, value)
{
Expression = expression;
}
public string Expression { get; }
}
public class C
{
public C(A<double> a)
{
_a = a;
}
public string Name { get { return _a.Name; } }
public double Value { get { return _a.Value; } }
protected A<double> _a;
}
public class D : C
{
public D(B b) : base(b)
{
}
public string Expression { get { return ((B)_a).Expression; } }
}
The line in question:
public string Expression { get { return ((B)_a).Expression; } }
Yes this is bad practice; like all downcasting (sometimes necessary to be sure; but that doesn't make it good).
The following code will generate a runtime exception:
A<double> myA = new A<double>("Test", 1.0d);
D test = new D(myA);
var boom = test.Expression; //InvalidCastException
Whereas with a different structure that wouldn't even compile. For example, modifying D to take a B instead of an A<double>
Try this, make the C class generic
public class C<T> where T : A<double>
{
public C(T thing)
{
_thing = thing;
}
protected T _thing;
}
Then D can be an instance of C with a generic argument of B
public D : C<B>
{
Public string Expression { get {return _thing.Expression;}}
}
I'm on my phone so please forgive.sny formatting or typo issues
Related
I am having an issue with Reflection, which I can't seem to find a solution for.
I have the following simple interface :
public interface IDataProperty<T>
{
public T Value { get; set; }
public int BytesCount();
public byte[] Serialize();
}
the struct which implements the interface above :
public struct IntProperty : IDataPropery<int>
{
private int _value;
public int Value { get => _value; set => _value = value; }
public int BytesCount()
{
return 4;
}
public byte[] Serialize()
{
return BitConverter.GetBytes(_value);
}
public IntDataProperty(int value) { _value = value; }
}
and a simple class to hold the values :
public class ValuesContainer
{
public IntProperty prop1;
public IntProperty prop2;
}
I am trying to call the Serialize() method on both prop1 and prop2 in my Processor class,
with no luck so far... :
public class Processor
{
public void ProccesData<T>(out T result) where T : ValuesContainer, new()
{
result = new T();
List<FieldInfo> dataFields = new List<FieldInfo>();
result.GetType().GetFields().ToList().ForEach(field => {
if(field.FieldType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDataProperty<>)))
{
dataFields.Add(field);
}
});
MethodInfo serializeMI = typeof(IDataProperty<>).GetMethod("Serialize");
foreach(FieldInfo field in dataFields)
{
Console.WriteLine(field.Name);
serializeMI.Invoke(field,null);
}
}
}
Running the code at this point gives me the following error :
'Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.'
I am aware that I need to get somehow to the instance behind the field variable, but have no idea how to do it.
Does anyone know a good way of doing what i am trying to achieve using other methods, or only Reflection is the way to go, and if the latter - what solutions do I have ?
Thanks in advance to all of you.
After the great help #JeroenMostert provided in the comments , i have been able to solve the issue at its roots. As long as Jeroen haven't provided an answer to be accepted as correct , I will just show his solution , so this question gets marked as answered. Still, the benefit here goes to #JeroenMostert
internal class Program
{
static void Main(string[] args)
{
ValuesContainer container = new ValuesContainer();
Processor processor = new Processor();
processor.ProccesData(out container);
}
}
public interface IDataProperty<T>
{
public void Serialize();
}
public struct IntProperty : IDataProperty<int>
{
private int _value;
public int Value { get => _value; set => _value = value; }
public int BytesCount()
{
return 4;
}
public void Serialize()
{
Console.WriteLine("I have been invoked !" + this.GetHashCode());
}
}
public class ValuesContainer
{
public IntProperty prop1;
public IntProperty prop2;
}
public class Processor
{
public void ProccesData<T>(out T result) where T : ValuesContainer, new()
{
result = new T();
List<FieldInfo> dataFields = new List<FieldInfo>();
result.GetType().GetFields().ToList().ForEach(field => {
if (field.FieldType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDataProperty<>)))
{
dataFields.Add(field);
}
});
foreach (FieldInfo field in dataFields)
{
Console.WriteLine("Invoking 'Serialize' method on fieldName :" + field.Name);
field.GetValue(result).GetType().GetMethod("Serialize").Invoke(field.GetValue(result), null);
}
}
}
I have 2 classes as you can see :
static void Main(string[] args)
{
object m = (??????)"salam";
}
public class A
{
public string name { set; get; }
public static implicit operator A(string _name)
{
A aa = new A();
aa.name = _name;
return aa;
}
}
public class B
{
public string family { set; get; }
public static implicit operator B(string _family)
{
B bb = new B();
bb.family = _family;
return bb;
}
}
I need to cast my string in runtime in this line :
object m = (??????)"salam";
Is there any solution to pass my class name as a string to cast my value .for example in runtime I need to cast "salam" to A or maybe B
The static cast is working good like this
object m = (A)salam";
object m = (B)"salam";
But I need to cast my string in runtime
Type x=null;
If(condition)
x can be type of A
else
x can be type of B
object m = (x)"salam";
You need to use Interfaces for such a need. The following code shows how to do so.
To simulate your situtation, I wrote a method to return either A or B based on time.
Here the list contains a bunch of objects which may be of Type A or B, depending on the second of execution. In the real-world scenario, you would get your types in various other ways.
public class StackOverflowQuestion
{
public static void Run()
{
List<IBase> list = new List<IBase>();
string types = "";
for (int i = 0; i < 10; i++)
{
var randomType = GiveMeARandomIBaseType();
System.Threading.Thread.Sleep(750);
IBase hello = randomType.Convert("salam");
list.Add(hello);
types += hello.GetType().Name + ",";
}
types = types.Trim(',');
//sample result : B,B,A,B,A,A,B,A,B,B
}
static IBase GiveMeARandomIBaseType() {
if (DateTime.Now.Second % 2 == 0)
return new A();
else
return new B();
}
}
public interface IBase {
public IBase Convert(string s);
}
public static class MyExtensions {
public static T Convert<T>(this string str, IBase b) where T : IBase {
try
{
return (T)b.Convert(str);
}
catch (Exception)
{
return default;
}
}
}
public class A : IBase
{
public IBase Convert(string s) {
return (A)s;
}
public string name { set; get; }
public static implicit operator A(string _name)
{
A aa = new A();
aa.name = _name;
return aa;
}
}
public class B : IBase
{
public IBase Convert(string s)
{
return (B)s;
}
public string family { set; get; }
public static implicit operator B(string _family)
{
B bb = new B();
bb.family = _family;
return bb;
}
}
I had a similar problem and after all the study and time, I was able to approach the desired result in the following way.
I used an internal method to access (the inside of) the class and this method returns the cast desired result.
Step 1: in class
public class A
{
public string Name { set; get; }
public static implicit operator A(string name)
{
return new A
{
Name = name
};
}
public A GetCasting(object a)
{
A i = (A)a;
return i;
}
}
public class B
{
public string Family { set; get; }
public static implicit operator B(string family)
{
return new B
{
Family = family
};
}
public B GetCasting(object b)
{
B i = (B)b;
return i;
}
}
Step 2: in controller or code
var className = "A";
var classMethod = "GetCasting";
var classType = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsClass && t.Name == className).FirstOrDefault();
var classInstance = Activator.CreateInstance(classType);
var castMethod = classType.GetMethod(classMethod);
var yourObject = "salam";
var objectData = new object[] { yourObject };
var resultObject = castMethod.Invoke(classInstance, objectData);
So my dilemma is that in order to access IntThing's or StringThing's MyProperty from UtilityThing<T>, I'm defining an interface with MyProperty and using it as the generic constraint on T in UtilityThing<T>. This is working, but seems redundant given that the same property is already defined in the abstract base. Am I missing a facet of design here, or is this actually the way it needs to be done in this instance?
public interface IThing {
string MyProperty { get; set; }
}
public abstract class Thing<T> {
protected string _MyProperty;
public abstract string MyProperty { get; set; }
public T OtherProperty { get; set; }
public string CommonMethod() {
return MyProperty + "foobar";
}
}
public class IntThing : Thing<int?>, IThing {
public override string MyProperty {
get { return _MyProperty; }
set { _MyProperty = value + OtherProperty.ToString(); }
}
}
public class StringThing: Thing<string>, IThing {
public override string MyProperty {
get { return _MyProperty; }
set { _MyProperty = OtherProperty + value; }
}
}
public class UtilityThing<T> where T: IThing, new() {
public T DoIt(SomeContext someContext, string name) {
string contextVal = someContext.GetValue(name);
var thing = new T { MyProperty = contextVal }
return thing;
}
}
You'll need to introduce a new generic type. Once the new type is introduced you can eliminate the need of the interface.
public class UtilityThing<T, I> where T : Thing<I>, new()
{
public T DoIt(SomeContext someContext, string name)
{
string contextVal = someContext.GetValue(name);
var thing = new T { MyProperty = contextVal };
return thing;
}
}
And you can use it like this:
var utility = new UtilityThing<IntThing, int?>();
So I have got these 2 instance types "FirstType" and "SecondType" which inherit from the mother class "ContaBancaria". They both return text from different textboxes. Basically, they do the same thing, but I need 2 instances for 2 different list types (I probably don't think the list has anything to do with my question, so I'll proceed not to go in detail)
Here are the instances:
private FirstType AddTypeFirst()
{
return new FirstType(textBoxNumber.Text,
textBoxBalance.Text,
textBoxName.Text,
textBoxAddress.Text,
textBoxBirth.Text);
}
private SecondType AddTypeSecond()
{
return new SecondType(textBoxNumber.Text,
textBoxBalance.Text,
textBoxName.Text,
textBoxAddress.Text,
textBoxBirth.Text);
}
Is there a way to return these 2 instances with the same method type?
EDIT:
What I meant was to return these 2 different types of instances with 1 single method, for example:
private [type?] AddInstance()
{
return new [type*] textBoxNumber.Text, //* the type could be FirstType or SecondType
textBoxBalance.Text,
textBoxName.Text,
textBoxAddress.Text,
textBoxBirth.Text);
}
EDIT 2:
ContaBancaria looks like this:
abstract class ContaBancaria
{
public string number { get; set; }
public string balance { get; set; }
public Client data { get; set; }
}
And, since there's Client...
class Client
{
public string name;
public string address;
public string birth;
}
Hope you get me.
You can use generic method and derrived classes I think.
For example, you have two classes and you want to receive one of them. Those classes are named "FirstSon" and "SecondSon" and both of them are derrived from class "Father".
class Father
{
string myName;
public string MyName
{
get { return myName; }
set { myName = value; }
}
public Father()
{
myName = "John";
}
}
class FirstSon : Father
{
string mySecondName;
public string MySecondName
{
get { return mySecondName; }
set { mySecondName = value; }
}
public FirstSon()
{
mySecondName = "Bill";
}
}
class SecondSon : Father
{
int age;
public int Age
{
get { return age; }
set { age = value; }
}
string mySecondName;
public string MySecondName
{
get { return mySecondName; }
set { mySecondName = value; }
}
public SecondSon()
{
mySecondName = "Drake";
age = 21;
}
}
And you have method GetObject(). This method is generic. It receives type of class, then checks what type it has received and returnes the new object with the same type.
public static T GetObject<T>() where T: Father
{
var firstSon = new FirstSon();
var secondSon = new SecondSon();
if (firstSon.GetType() == typeof(T))
return (T)Convert.ChangeType(firstSon, typeof(T));
return (T)Convert.ChangeType(secondSon, typeof(T));
}
It uses method Convert.ChangeType(object value, Type conversonType) and allows you to convert your object to your type.
But I am not convinced that this is a good idea according to How do I make the return type of a method generic?
Assuming you want to return the proper type based on the list being added to, you will need to write your own generic Add function, and use Reflection to figure out the type:
public static class Ext {
public static void AddInstancia<T>(this List<T> aList) where T : class {
if (typeof(T) == typeof(FirstType))
aList.Add(AddTypeFirst() as T);
else
aList.Add(AddTypeSecond() as T);
}
}
I see no good reason to do this - after all, you know the type of the list, just call the correct function for that list...
Instead of using Reflection, you could also use dynamic if you add some functions to each sub-type:
public class FirstType : Parent {
public FirstType MakeChild() {
return new FirstType();
}
}
public class SecondType : Parent {
public SecondType MakeChild() {
return new SecondType();
}
}
public static class Static<T> where T : new() {
public static dynamic Value = new T();
}
public static class Ext {
public static void AddInstance<T>(this List<T> aList) where T : new() {
aList.Add(Static<T>.Value.MakeChild());
}
}
Which you can call like
var list1 = new List<FirstType>();
list1.AddInstance();
Please excuse bursts of stupidity as I learn the intricacies of C# / .NET
Say I have three classes with multiple static properties (more than three but for arguments sake..)
CLASS FOO
public static A
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
CLASS BAR
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
CLASS YOO
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
And from another class I need to update one or several static properties in each class multiple times... How do I keep from writing multiple SWITCH statments like this...
public void updateVarx(string class, string varx)
{
string y = 'class'
SWITCH (y)
{
case FOO:
FOO.A = Varx;
break;
case BAR:
BAR.A = Varx;
break;
case YOO:
YOO.A = Varx;
break;
}
}
And then another one when I want to update B varY:
public void updateVary(string class, string vary)
{
string y = 'class'
SWITCH (y)
{
case FOO:
FOO.B = Vary;
break;
case BAR:
BAR.B = Vary;
break;
case YOO:
YOO.B = Vary;
break;
}
}
Since you are learning .net/c#, I guess i should warn you, using static properties is probably not the way to go in object oriented programming.
Static is global state and is dangerous. If you end up using multi-threaded code, you have to be super careful. If you need only one instance, just instantiate one, but don't go creating static properties on a class, unless you have a pretty good reason to add them (And I can't think of any right now).
In fact, in well designed, object oriented code you sould probably not have many if, switch, getters or setters either.
Let's say you need different behaviors on your classes, you can do it this way.
Interface ISecurity {
void UpdateVarX(int value);
void UpdateVarY(int value);
int GetValueX();
int GetValueX();
}
class Foo:ISecurity {
// Implement methods of the interface
}
class Bar:ISecurity {
// Implement methods of the interface
}
class Yoo:ISecurity {
// Implement methods of the interface
}
// This class is the class that uses your other classes
class Consumer
{
private ISecurity sec;
public Consumer(ISecurity sec) {
sec.UpdateVarX(25);
}
}
Or if as in your example, all your static classes have the same properties:
public class Settings {
public int A {get; set;}
public int B {get; set;}
public int C {get; set;}
}
public class NeedsToUseOtherClass {
public NeedsToUseOtherClass() {
Settings foo = new Settings();
Settings bar = new Settings();
Settings yoo = new Settings();
foo.setA(25);
}
}
Maybe I am not understanding the problem but if all your classes have the same exact properties then you can just pass the object (FOO, BAR, or YOO) into UpdateVarx or UpdateVary methods and just implement an interface? Something along these lines:
public class FOO : IHasStatus
{
public A
{
get / set A;
}
public B
{
get / set B;
}
public C
{
get / set C;
}
}
public void updateVarx(IHasStatus someObject, string varx)
{
someObject.A = varx;
}
public void updateVary(IHasStatus someObject, string vary)
{
someObject.B = vary;
}
If you don't need the concrete classes, you can abstract out the logic like so:
public class Status {
public string A {
get; set;
}
public string B {
get; set;
}
public string C {
get; set;
}
}
public static class StatusManager {
private static Dictionary<string, Status> statusMap = new Dictionary<string,Status>();
public static Status GetStatus(string name) {
Status status;
if (!statusMap.TryGetValue(name, out status))
statusMap[name] = status = new Status();
return status;
}
public static void SetStatus(string name, Status status) {
statusMap[name] = status;
}
public static void UpdateVarx(string name, string varx) {
GetStatus(name).A = varx;
}
// ...
}
If you are a fan of the javascript way of solving multiple switch cases like this
you can always wrap up the switch handlers as Actions and toss them in a Dictionary.
For example : (Source obtained from here)
public class SwitchCase : Dictionary<string,Action>
{
public void Eval(string key)
{
if (this.ContainsKey(key))
this[key]();
else
this["default"]();
}
}
//Now, somewhere else
var mySwitch = new SwitchCase
{
{ "case1", ()=>Console.WriteLine("Case1 is executed") },
{ "case2", ()=>Console.WriteLine("Case2 is executed") },
{ "case3", ()=>Console.WriteLine("Case3 is executed") },
{ "case4", ()=>Console.WriteLine("Case4 is executed") },
{ "default",()=>Console.WriteLine("Default is executed") },
};
mySwitch.Eval(c);
Below code uses all kinds of hacks, not really recommended in production code unless you have a very good reason.
using System;
using System.Linq;
namespace ConsoleApplication1
{
static class Program
{
private static void SetStaticProperty(string className, string propName, string varx)
{
//This sucks, I couldnt find the namespace with easily through reflection :(
string NAMESPACE = "ConsoleApplication1";
Type t = Type.GetType(NAMESPACE + "." + className);
t.GetProperties().Where(p => p.Name == propName).First().SetValue(null, varx, null);
}
public static void updateVarx(string className, string varx)
{
SetStaticProperty(className, "A", varx);
}
public static void updateVary(string className, string vary)
{
SetStaticProperty(className, "B", vary);
}
static void Main(string[] args)
{
updateVarx("Foo", "FooAstring");
updateVarx("Bar", "BarAstring");
updateVarx("Yod", "YodAstring");
updateVary("Foo", "FooBstring");
updateVary("Bar", "BarBstring");
updateVary("Yod", "YodBstring");
Console.WriteLine(Foo.A);
Console.WriteLine(Foo.B);
Console.WriteLine(Bar.A);
Console.WriteLine(Bar.B);
Console.WriteLine(Yod.A);
Console.WriteLine(Yod.B);
Console.ReadLine();
}
}
class Foo
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
class Bar
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
class Yod
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
}
You can use dictionary as configuration and remove the switch statement
Create a dictionary and add append data as below for mapping
//Have dictionary setted up
Dictionary<string, dynamic> m_Dictionary = new Dictionary<string, dynamic>();
m_xmlDictionary.Add("classA",FOO);
m_xmlDictionary.Add("classB",BAR);
m_xmlDictionary.Add("classC",BAR);
//Have dictionary setted up
//change the function as below
public void updatevarx(string class, string varx)
{
m_Dictionary[class].A=varx // Replaced switch statement
}
//while calling use
updatevarx("classC","abc!");// This will assign BAR.A with abc!