I am working with C# where I need to create a single method which can accept parameter as a class name.
like: -
Class A
{
public string name {get;set;}
}
Class B
{
public int age {get;set;}
}
Class C
{
public decimal salary {get;set;}
}
A function will call MethodABC based on some condition.
Function1(){
A obj = new A();
MethodaBC(obj);
}
Function2(){
B obj = new B();
MethodaBC(obj);
}
Function3(){
C obj = new C();
MethodaBC(obj);
}
Method definition is: -
Static MethodABC(....)
Within MethodABC, I need to do some operation based on which class object has been passed in MethodABC.
You can always use the activator class to help you.
Example:
Type type = typeof(MyClass);
MyClass instance = (MyClass)Activator.Create(type);
//method example
public void ClassGet(string MyClassName,string blabla)
{
object instance = Activator.Create(MyClassName);
}
// Call it like:
Gold g = new Gold();
g.ClassGet("MyClass", "blabla");
You can pass the class as object as well:
//method example
public void ClassGet(MyClass MyClassName,string blabla)
{
object instance = Activator.Create(MyClassName);
}
// Call it like:
Gold g = new Gold();
g.ClassGet(MyClass, "blabla");
Related
I have 3 different classes:
class A
{
public int property1;
public int property2;
// so on..
}
class B
{
public int property11;
public int property22;
//so on.
}
class Consumer
{
public int property111;
public int property222;
//so on.
}
// Business logic in other class
if (someCondition)
{
var serviceCall1 = GetValuesForClassA();
A obj = serviceCall.Response;
}
else if (someOtherCondition)
{
var serviceCall2 = GetValuesForClassB();
B obj = serviceCall2.Response;
}
After I get the values of particular type I am assigning it to the properties of Consumer type via a generic function as below:
private void ApplyProperties<T>(T serviceResponse, Consumer obj)
where T: class
{
if (serviceResponse.GetType().Name == "A") // where A = class name
{
A newObj = (A)(object)serviceResponse;
//Assign properties of Consumer obj here.
}
else if(serviceResponse.GetType().Name == "B") // where B = class name
{
B newObj = (B)(object)serviceResponse;
//Assign properties of Consumer obj here.
}
}
I have followed this example. I was unclear on how to change my code in a more cleaner way, hence the question.
You can use pattern matching
if (serviceResponse is A newObj) // where A = class name
{
//Assign properties of Consumer obj here.
}
https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching
In repository I keep some instances which live throughout the lifetime of my application but sometimes I need an immediate replacement for such instance with another instance and LightInject even if passing the new instance to the container.GetInstance constructor override.
Here is a snippet showing the problem:
internal class ClassA
{
public string Name { get; private set; }
public ClassA(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
internal class ClassB
{
public ClassA A { get; private set; }
public ClassB(ClassA a)
{
A = a;
}
public override string ToString()
{
return string.Format("I contain {0}", A);
}
}
private void TestContainer()
{
var container = new LightInject.ServiceContainer();
var a1 = new ClassA("A instance 1");
container.Register(x => a1);
container.Register<ClassB>();
var a2 = new ClassA("A instance 2");
var bwitha1 = container.GetInstance<ClassB>();
if(bwitha1.A != a1)
{
throw new InvalidOperationException("This will not happen");
}
var bwitha2 = container.GetInstance<ClassA, ClassB>(a2);
if(bwitha2.A != a2)
{
throw new InvalidOperationException("Something went wrong here");
}
}
Why LightInject previously registered instance takes precedence if I give explicit instance in GetInstance call? How to get around the issue and construct the object with an alternative instance of one of the arguments?
In the current version of LightInject you need to provide a factory if you want to use runtime arguments.
The following workaround might work for you.
using LightInject;
class Program
{
static void Main(string[] args)
{
var container = new ServiceContainer();
container.Register<Bar>();
container.Register<Foo>();
container.Register<Bar, Foo>((factory, bar) => new Foo(bar), "FooWithRuntimeArgument");
var instance = container.GetInstance<Foo>();
var instanceWithRuntimeArgument = container.GetInstance<Bar, Foo>(new Bar(), "FooWithRuntimeArgument");
}
}
public class Foo
{
public Foo(Bar bar) {}
}
public class Bar {}
Let's say I have three classes A, B and C as below, A and B have property Pro1 and Pro2 with Type C:
class A
{
public C Pro1 {get; set; }
}
class B
{
public C Pro2 { get; set; }
}
public class C
{
public void Do()
{
//How to get Type of object to reference to current object C
//Example: Either type A or B
}
}
In the method Do of class C I want to get which current parent object to reference to current object C (via Pro1 and Pro2). In this sample either A or B, but in general, it could be very dynamic:
var a = new A() { Pro1 = new C() };
a.Pro1.Do(); //will get Type A in Do
var b = new B() { Pro2 = new C() };
b.Pro2.Do(); //with get Type B in Do
Which approach I can achieve this?
You could pass the "parent" object as a parameter to the C constructor:
public class C
{
private readonly object _parent;
public C(object parent)
{
_parent;
}
public void Do()
{
Type type = _parent != null ? _parent.GetType() : null;
// Do something with type...
}
}
var a = new A() { Pro1 = new C() };
a.Pro1.Do(); //will get Type A in Do
var b = new B() { Pro2 = new C() };
b.Pro2.Do(); //with get Type B in Do
By this, you already know which object is making the call (a or b); what you are doing may not make sense then. If so, you can always resolve this with simple inheritance
C a=new A();
C b=new B();
and the ctors A or B can be inserted an identity of the caller.
Thomas Levesque has given one way of adding more info to C to achive this. If it is the type rather than the particular instance you want to store in C, you could make C generic, as in:
class A
{
public C<A> Pro1 { get; set; }
}
class B
{
public C<B> Pro2 { get; set; }
}
public class C<T> where T : class // maybe you want to add other "where" constraints on T
{
public void Do()
{
// you can use T in here
}
}
How can I pass an object of a "MyClass" (C#) by Parameter-by-Value to a method? example:
MyClass obj = new MyClass();
MyClass.DontModify(obj); //Only use it!
Console.Writeline(obj.SomeIntProperty);
...
public static void DontModify(MyClass a)
{
a.SomeIntProperty+= 100;// Do something more meaningful here
return;
}
By default object types are passed by value in C#. But when you pass a object reference to a method, modifications in the object are persisted. If you want your object to be inmutable, you need to clone it.
In oder to do it, implement the ICloneable interface in your class. Here is a mock example of how to use ICloneable:
public class MyClass : ICloneable
{
private int myValue;
public MyClass(int val)
{
myValue = val;
}
public void object Clone()
{
return new MyClass(myValue);
}
}
By default, it is passed by value. However, you're passing the object reference by value, which means you can still edit values within the object.
In order to prevent the object from being able to change at all, you would need to actually clone the object prior to passing it into your method. This would require you to implement some method of creating a new instance that is a copy of your original object, and then passing in the copy.
public static void DontModify(MyClass a)
{
MyClass clone = (MyClass)a.Clone();
clone.SomeIntProperty+= 100;// Do something more meaningful here
return;
}
You could create a Clone method on your object to pass the return value to your method. C# cannot pass reference types by value so this might be a good alternative.
public MyClass CreateClone()
{
return new MyClass() { SomeIntProperty = this.SomeIntProperty };
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person()
{
Name = "Alsafoo",
Address = new Address()
{
City = "Chicago"
}
};
Person p2 = new Person(p1.Address);
p2 = p1.GetClone(CloningFlags.Shallow);
p2.Name = "Ahmed";
p2.Address = new Address(){City = "Las Vegas"};
Console.WriteLine("p1 first name: {1} --- p1 city: {2} {0}p2 first name: {3} ---- p2 city: {4}",
Environment.NewLine, p1.Name, p1.Address.City, p2.Name, p2.Address.City);
Console.ReadKey();
}
}
public class Person
{
public Person()
{}
public Person(Address a)
{
Address = a;
}
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
}
Download this extension
https://www.nuget.org/packages/CloneExtensions/1.2.0
Created a Extention method
using System.Text.Json;
namespace Student.Utilities
{
public static class CloneExtension
{
public static T Clone<T>(this T cloneable) where T : new()
{
var toJson = JsonSerializer.Serialize(cloneable);
return JsonSerializer.Deserialize<T>(toJson);
}
}
}
Now, while calling, call it like this to pass the clone to another method:
public void CreateStudent(Student student)
{
Student clonedStudent = student.Clone<Student>();
_repository.CreateStudent(clonedStudent);
}
How would you share the same object between two other objects? For instance, I'd like something in that flavor:
class A
{
private string foo_; // It could be any other class/struct too (Vector3, Matrix...)
public A (string shared)
{
this.foo_ = shared;
}
public void Bar()
{
this.foo_ = "changed";
}
}
...
// inside main
string str = "test";
A a = new A(str);
Console.WriteLine(str); // "test"
a.Bar();
Console.WriteLine(str); // I get "test" instead of "changed"... :(
Here, I don't want to give a ref to the Bar method. What I want to achieve is something that would look like that in C++:
class A
{
int* i;
public:
A(int* val);
};
A::A (int* val)
{
this->i = val;
}
I read there is some ref/out stuff, but I couldn't get what I'm asking here. I could only apply some changes in the methods scope where I was using ref/out arguments...
I also read we could use pointers, but is there no other way to do it?
This has nothing to do with sharing objects. You passed a reference to a string into the A constructor. That reference was copied into the private member foo_. Later, you called B(), which changed foo_ to "changed".
At no time did you modify str. str is a local variable in main. You never passed a reference to it.
If you had wanted to change str, you could have defined B as
public void Bar(ref string s)
{
this.foo_ = "changed";
s = this.foo_;
}
Consider:
public class C
{
public int Property {get;set;}
}
public class A
{
private C _c;
public A(C c){_c = c;}
public void ChangeC(int n) {_c.Property = n;}
}
public class B
{
private C _c;
public B(C c){_c = c;}
public void ChangeC(int n) {_c.Property = n;}
}
in main:
C myC = new C() {Property = 1;}
A myA = new A(myC);
B myB = new B(myC);
int i1 = myC.Property; // 1
myA.ChangeC(2);
int i2 = myC.Property; // 2
myB.ChangeC(3);
int i3 = myC.Property; // 3
Wrap your string inside a class. You need to do this because strings are immutable. Any attempt to change a string actually results in a new string.
class Foo {
class StringHolder {
public string Value { get; set; }
}
private StringHolder holder = new StringHolder();
public string Value {
get { return holder.Value; }
set { holder.Value = value; }
}
public Foo() { }
// this constructor creates a "linked" Foo
public Foo(Foo other) { this.holder = other.holder; }
}
// .. later ...
Foo a = new Foo { Value = "moose" };
Foo b = new Foo(a); // link b to a
b.Value = "elk";
// now a.Value also == "elk"
a.Value = "deer";
// now b.Value also == "deer"
I would split my answer to 2 parts:
1) If the variable is a reference type than it is already shared since you pass its reference to all interested objects. The only thing you should pay attention is that the reference type instances are mutable.
2) If the variable is a value type than you would have to use ref or out or some wrapper that is mutable and you can change the value inside the wrapper using a method or a property.
Hope that helps.
You need to pass the paramter as a reference to your method,
class A
{
private string foo_; // It could be any other class/struct too (Vector3, Matrix...)
public A(string shared)
{
this.foo_ = shared;
}
public void Bar(ref string myString)
{
myString = "changed";
}
}
static void Main()
{
string str = "test";
A a = new A(str);
Console.WriteLine(str); // "test"
a.Bar(ref str);
Console.WriteLine(str);
}
When a variable is a string, it is a reference.
Try to clone the string. http://msdn.microsoft.com/en-us/library/system.string.clone.aspx