user3541486
user3541486

Reputation: 39

Is it possible to change an object type in C#

I am having some problem in order to meet a client request.

I will try to keep the example very simple just give an idea of the problem and hopefully come up with a solution.

At this point we have a class "Shape" for example, and shape has some specializations, it can be square, triangle etc.

so far so good, everything working great.

Now for some reason my client wants to change a square that already exist in the system into a triangle but keep all the data from shape.

is that possible? any workarounds for that?

Upvotes: 3

Views: 4419

Answers (7)

Uri Abramson
Uri Abramson

Reputation: 6175

You can't change the type but you can solve this with a proper design. If the idea is that each object is a Shape and it has additional information, which has to be replacable, it makes sense that it would be held as a separate member. For example (pseudo):

public class ShapeContainer 
{
 public int x { get; set; }
 public int y { get; set; }

 public ISpecificShape SpecificShape { get; set; }
}

public class Triangle : ISpecificShape 
{
// ...
// ...
}

public class Rectange : ISpecificShape 
{
// ...
// ...
}

This way, you can change the specific shape.

If you want it to be typed, you could add the following generic Get function to Shape:

GetSpecificShape<T>() where T : ISpecificShape 
{
 return (T)this.SpecificShape;
}

This will raise an exception if the data types do not match but that's consistent with your design requirements.

What do you think?

Upvotes: 1

Sten Petrov
Sten Petrov

Reputation: 11040

Define and implement a virtual Clone() method in your Shape class. You have two "reasonable" options. Whichever implementation you choose you can't just "invent" the data that isn't there - the square has one side size and the triangle has 3.

First option is to manually copy all fields around:

class Shape{

  public virtual Shape Clone(Shape target = null){
    if (target == null) target = new Shape();
    target.Prop1 = this.Prop1;
    return target;
  } 
}

class Square{
  public override Shape Clone(Shape target = null){
    if (target == null) target = new Square();
    base.Clone(target);
    if (target.GetType() == typeof(Square)){
      target.PropSquare1 = this.PropSquare1; // some casting etc
    }
  } 
}

// change type: var triangle = new Triangle(); square.Clone(triangle);

Second option, which I prefer trades in performance for convenience. It is to use a serializer to serialize the shape as one kind and deserialize as another. You may need to process the serialized result in-between. Below is a pseudo code version:

class Shape{
  public virtual T Clone<T>() where T: Shape{
    var data = JsonConvert.Serialize(this);
    data = data.Replace("Square","Triangle");
    return JsonConvert.Deserialize<T>(data);
  }
}

Upvotes: -2

Daniel Br&#252;ckner
Daniel Br&#252;ckner

Reputation: 59645

You can not change the runtime type of an object. Just create a new triangle, copy over all the relevant values and throw away the square. This may of course become tricky if the square is already referenced by a lot of other objects because you will have to update all references.

If replacing the object is not an option, you will probably have to come up with a generic shape class that can act as any kind of shape. This class could, for example, be a thin wrapper around an instance of one of the concrete shape classes. This enables you to just replace the wrapped square with a new triangle while the outside world can keep all the references to the wrapper class.

Upvotes: 5

bokan
bokan

Reputation: 3692

What you need is called inheritance.

Here is a model of that :

Create a StrokeStyle class

  • width
  • color
  • type (dashed, solid)

Create a FillStyle class

  • color
  • type (solid, gradient)

Create a VectorShape class that has strokeStyle and fillStyle properties (each being an instance of the classes).

Create Square and Triangle class, both being inheriting VectorShape class. They will share VectorShape properties. You will have to replace your square instance by a new Triangle instance and copy the properties you want to keep.

You can also do a single class with a shapetype property wich will be "square" or "triangle"... then you gain the benefit of changing the type without replacing the object. But you wil have to handle the shapetype in all methods ie : computeArea(). And this will lead to a huggly unmanagable code. This is possible but it's the bad way.

Upvotes: 0

Marc Wittmann
Marc Wittmann

Reputation: 2362

There is a Convert.ChangeType(dObject, typeof(SomeClass));

But for the conversion to succeed, value must implement the IConvertible interface, because the method simply wraps a call to an appropriate IConvertible method. The method requires that conversion of value to conversionType be supported.

Upvotes: -2

Codor
Codor

Reputation: 17605

It is not possible in terms of replacing the type of an existing object without creating a new object of the desired type and manually updating all references to it (which is highly error-prone) - which I would consider a workaround.

Design-wise, the if the "type" (in the sense of behaviour, not of an actual type in the static type system) needs to be flexible, the problem can be solved with delegation. The object itself would remain the same, but a delegate is exchanged.

Upvotes: 1

mason
mason

Reputation: 32694

You can convert between data types. The results can be placed in a new object. The type of the original object does not change. But usually you only provide a mechanism for this when it makes sense to do so. In the case of converting a square into a triangle, I don't see how that would make sense but maybe there's something about your specific application where it would make sense (ie, convert a square to a triangle with the same size perimeter or area).

See Using Conversion Operators on MSDN for examples of converting between different types.

From Casting and Type Conversions on MSDN:

Because C# is statically-typed at compile time, after a variable is declared, it cannot be declared again or used to store values of another type unless that type is convertible to the variable's type. For example, there is no conversion from an integer to any arbitrary string. Therefore, after you declare i as an integer, you cannot assign the string "Hello" to it, as is shown in the following code.

Upvotes: -1

Related Questions