繁体   English   中英

是否可以在 C# 中更改对象类型

[英]Is it possible to change an object type in C#

为了满足客户的要求,我遇到了一些问题。

我会尽量让这个例子非常简单,只是给出一个问题的想法,并希望提出一个解决方案。

在这一点上,我们有一个类“形状”,例如,形状有一些特化,它可以是正方形、三角形等。

到目前为止一切顺利,一切都很好。

现在出于某种原因,我的客户想要将系统中已经存在的正方形更改为三角形,但保留所有数据的形状。

那可能吗? 任何解决方法?

您不能更改对象的运行时类型。 只需创建一个新三角形,复制所有相关值并丢弃正方形。 如果正方形已经被许多其他对象引用,这当然会变得棘手,因为您必须更新所有引用。

如果替换对象不是一种选择,您可能必须想出一个可以充当任何类型形状的通用形状类。 例如,此类可以是围绕其中一个具体形状类的实例的薄包装器。 这使您只需用新三角形替换包装的正方形,而外部世界可以保留对包装类的所有引用。

在不创建所需类型的新对象并手动更新对它的所有引用(这很容易出错)的情况下替换现有对象的类型方面是不可能的 - 我会考虑一种解决方法。

在设计方面,如果“类型”(在行为意义上,而不是静态类型系统中的实际类型)需要灵活,则可以通过委托解决问题。 对象本身将保持不变,但交换了一个委托。

您无法更改类型,但可以通过适当的设计解决此问题。 如果想法是每个对象都是一个 Shape 并且它有附加信息,这些信息必须是可替换的,那么将它作为一个单独的成员保存是有道理的。 例如(伪):

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 
{
// ...
// ...
}

这样,您可以更改特定的形状。

如果您希望输入它,您可以将以下通用 Get 函数添加到 Shape:

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

如果数据类型不匹配但与您的设计要求一致,这将引发异常。

你怎么认为?

你需要的是继承。

这是一个模型:

创建一个 StrokeStyle 类

  • 宽度
  • 颜色
  • 类型(虚线,实线)

创建一个 FillStyle 类

  • 颜色
  • 类型(实心、渐变)

创建一个 VectorShape 类,它具有 strokeStyle 和 fillStyle 属性(每个都是这些类的一个实例)。

创建 Square 和 Triangle 类,它们都继承了 VectorShape 类。 它们将共享 VectorShape 属性。 您必须用新的 Triangle 实例替换您的 square 实例并复制您想要保留的属性。

您还可以使用 shapetype 属性执行单个类,该类将是“正方形”或“三角形”……然后您可以获得更改类型而不替换对象的好处。 但是您必须在所有方法中处理 shapetype,即:computeArea()。 这将导致代码难以管理。 这是可能的,但这是不好的方式。

您可以在数据类型之间进行转换。 结果可以放在一个新的对象中。 原始对象的类型不会改变 但通常你只在有意义的时候为此提供一种机制。 在将正方形转换为三角形的情况下,我不知道这有什么意义,但也许您的特定应用程序有一些有意义的地方(即,将正方形转换为具有相同大小周长或面积的三角形) )。

有关在不同类型之间转换的示例,请参阅 MSDN 上的使用转换运算符

来自 MSDN 上的转换和类型转换

因为 C# 在编译时是静态类型的,所以在声明变量后,不能再次声明它或用于存储其他类型的值,除非该类型可转换为变量的类型。 例如,没有从整数到任意字符串的转换。 因此,在将 i 声明为整数后,不能为其分配字符串“Hello”,如下面的代码所示。

Shape类中定义并实现虚拟Clone()方法。 你有两个“合理”的选择。 无论您选择哪种实现,您都不能只是“发明”不存在的数据 - 正方形有一侧尺寸,三角形有 3。

第一个选项是手动复制所有字段:

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
    }
  } 
}

// 改变类型:var triangle = new Triangle(); square.Clone(三角形);

第二种选择,我更喜欢为了方便而牺牲性能。 就是使用序列化器将形状序列化为一种,反序列化为另一种。 您可能需要处理中间的序列化结果。 下面是一个伪代码版本:

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

有一个 Convert.ChangeType(dObject, typeof(SomeClass));

但是要使转换成功,value 必须实现 IConvertible 接口,因为该方法只是包装了对适当 IConvertible 方法的调用。 该方法要求支持值到conversionType 的转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM