Method that returns instance of subclass - c#

Here's a simple class and a derived class:
class A { public int val; }
class B : A { }
I'd like a method Inc which works on both A and B instances that returns a new instance with val incremented by 1.
One way to approach this is to define Inc as an extension method:
static class Extensions
{
public static T Inc<T>(this T obj) where T : A, new()
{
return new T() { val = obj.val + 1 };
}
}
This seems to work. In the following example, a0.val is 11 and b0.val is 21.
var a = new A() { val = 10 };
var b = new B() { val = 20 };
var a0 = a.Inc();
var b0 = b.Inc();
My question is, is there a way to define Inc as a direct member of A and have it work as above?
If I define A like this:
class A
{
public int val;
public T Inc<T>() where T : A, new()
{
return new T() { val = val + 1 };
}
}
I then need to qualify the type when I call Inc:
var a = new A() { val = 10 };
var b = new B() { val = 20 };
var a0 = a.Inc<A>();
var b0 = b.Inc<B>();
Is there a way to go the member method route without having to qualify the type?

I don't think it's possible without implementing a new version of the method on each subclass, i.e,:
class A
{
public int val;
public virtual A Inc()
{
return new A { val = val + 1 };
}
}
class B : A
{
public new B Inc()
{
return new B { val = val + 1 };
}
}

So, you practically want to create clone of object with different value for some field:
class A {
public int val;
protected virtual A CloneInternal() {
return (A)MemberwiseClone();
}
public A Inc() {
A a=CloneInternal();
++a.val;
return a;
}
}
class B:A {
public new B Inc() {
return (B)base.Inc();
}
}
static void Main() {
A a=new B();
a=a.Inc();
Console.WriteLine(a.GetType());
}

Neither I don't think it's possible. You should provide a hint in order to make compiler guesses proper type for T.
You might try with static method:
public static T Inc<T>(T source) where T : A, new()
{
return new T() { val = source.val + 1 };
}
Then,
var b = new B { val = 20 };
var b0 = A.Inc(b);
But it's not an answer since you wanted a member method. I would rather go with extensions method.

abstract class Base
{
public int val { get; set; }
public virtual Base Inc() { return null; }
}
class A : Base
{
public override Base Inc()
{
return new A { val = val + 1 };
}
}
class B : A
{
public override Base Inc()
{
return new B { val = val + 2 };
}
}
Maybe using a abstract base class is better....
Base bClass = new B();
B bInc = bClass.Inc() as B;

One more way
interface IInc
{
int val { get; set; }
IInc GetNew();
}
class A : IInc
{
public int val
{
get;
set;
}
public virtual IInc GetNew()
{
return new A();
}
public IInc Inc()
{
var newObj = GetNew();
newObj.val++;
return newObj;
}
}
class B : A
{
public override IInc GetNew()
{
return new B();
}
}
and use like
var a = new A() { val = 10 };
var b = new B() { val = 20 };
var a0 = a.Inc();
var b0 = b.Inc();
Console.WriteLine(a0.val);
Console.WriteLine(b0.val);

Related

Dynamic cast in c# in runtime

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);

Printing list of objects

I have the below class, how do I print the list of objects in format [1,[2,3,8],[[]],10,[]] in C#?
public class InnerList
{
private int val;
private boolean isValue;
private List<InnerList> intList;
}
public string ConvertToString()
{
if (this.isValue)
{
return this.val + "";
}
else
{
return this.intList.ToString();
}
}
In my caller, I will use something like below to print the list of objects in format [1,[2,3,8],[[]],10,[]]
System.out.println(list);
My question is how to achieve this in c#?
Solution:
public class InnerList
{
//public only for simple initialization at usage example
public int val;
public bool isValue;
public List<InnerList> intList;
public override string ToString()
{
if (isValue)
return val.ToString();
return String.Format("[{0}]", intList == null ? "" : String.Join(", ", intList.Select(x => x.ToString())));
}
}
Usage:
var test = new InnerList
{
intList = new List<InnerList> {
new InnerList { isValue = true, val = 1 },
new InnerList { isValue = true, val = 2 },
new InnerList
{
intList = new List<InnerList> {
new InnerList { isValue = true, val = 13 },
new InnerList { isValue = true, val = 23 },
new InnerList()
}
}
}
};
Console.WriteLine(test);//[1, 2, [13, 23, []]]
Welcome to C# world!
I can't understand what you trying to do, but i can show you how we do in by C#:
public class InnerList
{
public int Value
{
get
{
return this.intList.Count;
}
}
public bool HasValue { get; set; }
private List<InnerList> intList;
public static implicit operator string(InnerList list)
{
return list.ToString();
}
public override string ToString()
{
if (this.HasValue)
{
return this.Value.ToString();
}
else
{
return this.intList.ToString();
}
}
}
It looks like you might run into the problem of circular them references here. Because an InnerList could reference its own parent in its intList. That is why I would recommend a serializer to do the job for you. It knows how to handle these circular references. I'm using Newtonsoft.Json here.
public override string ToString()
{
var settings = new JsonSerializerSettings();
settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
return JsonConvert.SerializeObject(this, settings);
}

C# Assign an object from class B to class A

I have Two Classes.
Class A:
public class A {
prop string p1 { get; set; }
prop string p2 { get; set; }
prop string p3 { get; set; }
}
Class B:
public class B {
prop string p1 { get; set; }
prop string p3 { get; set; }
}
Now assume we have an object from class B and we want to assign it to object from class A.
B b_obj = new B(){
p1 = "something",
p2 = "something else"
}
A a_obj = new A(){
p1 = b_obj.p1,
p3 = b_obj.p3,
}
I think the above solution is not best way.
What is best practice to assign b_obj to another object from class A?
Tip : All property in class B has a similar property in class A
You can always implement an implicit or explicit cast operator:
public class B
{
public static explicit operator A(B b)
{
return new A() {
p1 = b_obj.p1,
p3 = b_obj.p3,
}
}
//...
}
And now, you can simply write any time you need an A from a B:
var a = (A)b;
If you don't have access to either A or B then you could implement an extension method:
public static A ToA(this B b)
{
return ...
}
And the use would be similar:
var a = b.ToA();
You can use automapper
http://automapper.org/
Then you can use it like this:
AutoMapper.Mapper.CreateMap<A, B>();
var a = ...
var model = AutoMapper.Mapper.Map<B>(a);
You can use AutoMapper (see denisv's answer) which provides mappings between classes based on name. You can then customize your mappings if you want to.
You can also write some extension methods:
public static class Extensions
{
public A ToA(this B b)
{
return new A()
{
p1 = b_obj.p1,
p3 = b_obj.p3,
};
}
}
First of all initialize B class and set values. Then create such a class:
public static void CopyPropertyValues(object source, object destination)
{
var destProperties = destination.GetType().GetProperties();
foreach (var sourceProperty in source.GetType().GetProperties())
{
foreach (var destProperty in destProperties)
{
if (destProperty.Name == sourceProperty.Name &&
destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
{
destProperty.SetValue(destination, sourceProperty.GetValue(
source, new object[] { }), new object[] { });
break;
}
}
}
}
and pass A and B class to this class as Parameter

C# editing and adding function to nested class of abstract class

I have the abstract class shown below. It's nested class B is where I would like to define new functions.
public abstract class A {
public string varA = "Default";
public class B {
public B() {
}
public abstract somethingCool(int[] val);
}
}
public class C:A {
//set B functions
}
Is there a particular reason you NEED B to be a nested class? Why not just let your A class have a property of type B? Also, the somethingCool method needs a return type.
public abstract class A
{
public string varA = "Default";
public B InstanceOfB { get; set; }
}
public abstract class B
{
public abstract void SomethingCool(int[] val);
}
public class C : A
{
public override void SomethingCool(int[] val)
{
//do something cool
}
}
I'm not sure what you are trying to do, but if you want to implement B's functions from C, then mark B as abstract and subclass it in C. You can then override the abstract somethingCool method. Something like this:
public abstract class A
{
public string varA = "Default";
public abstract class B
{
public B() {}
public abstract void somethingCool(int[] val);
}
public void Foo(B bar, int[] val)
{
bar.somethingCool(val);
}
}
public class C : A
{
// set B functions
public class D : A.B
{
public override void somethingCool(int[] val)
{
for (int i = 0; i < val.Length; ++i)
{
System.Console.Write(string.Format("{0} ", val[i]));
}
}
}
}
Note that you can also subclass B from outside C:
public class E : A.B
{
public override void somethingCool(int[] val)
{
for (int i = val.Length - 1; i >= 0; --i)
{
System.Console.Write(string.Format("{0} ", val[i]));
}
}
}
Results:
public class Test
{
public void Test()
{
int[] val = new int[] { 1, 2, 3 };
var C = new C();
var D = new C.D();
C.Foo(D, val); // should print 1 2 3
var E = new E();
C.Foo(E, val); // should print 3 2 1
}
}

Setting properties from one class to another via GetProperties

here is a simple example to clear my intentions.
class A {
public int Id
public string Name
public string Hash
public C c
}
class B {
public int id
public string name
public C c
}
class C {
public string name
}
var a = new A() { Id = 123, Name = "something", Hash = "somehash" };
var b = new B();
I want to set b's properties from a. I have tried something but no luck.
public void GenericClassMatcher(object firstModel, object secondModel)
{
if (firstModel != null || secondModel != null)
{
var firstModelType = firstModel.GetType();
var secondModelType = secondModel.GetType();
// to view model
foreach (PropertyInfo prop in firstModelType.GetProperties())
{
var firstModelPropName = prop.Name.ElementAt(0).ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture) + prop.Name.Substring(1); // lowercase first letter
if (prop.PropertyType.FullName.EndsWith("Model"))
{
GenericClassMatcher(prop, secondModelType.GetProperty(firstModelPropName));
}
else
{
var firstModelPropValue = prop.GetValue(firstModel, null);
var secondModelProp = secondModelType.GetProperty(firstModelPropName);
if (prop.PropertyType.Name == "Guid")
{
firstModelPropValue = firstModelPropValue.ToString();
}
secondModelProp.SetValue(secondModel, firstModelPropValue, null);
}
}
}
}
What shall I do?
It sounds like you are trying to map one class to another. AutoMapper is the best tool I've come across to do this.
public class A
{
public int Id;
public string Name;
public string Hash;
public C c;
}
public class B
{
public int id;
public string name;
public C c;
}
public class C
{
public string name;
}
class Program
{
static void Main(string[] args)
{
var a = new A() { Id = 123, Name = "something", Hash = "somehash" };
var b = new B();
AutoMapper.Mapper.CreateMap<A, B>();
b = AutoMapper.Mapper.Map<A, B>(a);
Console.WriteLine(b.id);
Console.WriteLine(b.name);
Console.ReadLine();
}
}

Categories

Resources