Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:将基类转换为子类_C#_Oop_Class - Fatal编程技术网

C#:将基类转换为子类

C#:将基类转换为子类,c#,oop,class,C#,Oop,Class,我有一个类,NetworkClient作为基类: using System.IO; using System.Net.Sockets; using System.Threading.Tasks; namespace Network { using System; using System.Collections.Generic; using System.Linq; using System.Text; public class NetworkClient { public Netw

我有一个类,NetworkClient作为基类:

using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace Network
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class NetworkClient
{
    public NetworkClient()
    {
        tcpClient = new TcpClient();
    }
    public NetworkClient(TcpClient client)
    {
        tcpClient = client;
    }

    public virtual bool IsConnected
    {
        get;
        private set;
    }
    private StreamWriter writer { get; set; }
    private StreamReader reader { get; set; }

    private TcpClient tcpClient
    {
        get;
        set;
    }

    public virtual NetworkServerInfo NetworkServerInfo
    {
        get;
        set;
    }

    public async virtual void Connect(NetworkServerInfo info)
    {
        if (tcpClient == null)
        {
            tcpClient=new TcpClient();
        }
        await tcpClient.ConnectAsync(info.Address,info.Port);
        reader = new StreamReader(tcpClient.GetStream());
        writer = new StreamWriter(tcpClient.GetStream());
    }

    public virtual void Disconnect()
    {
        tcpClient.Close();            
        reader.Dispose();

        writer.Dispose();
    }

    public async virtual void Send(string data)
    {
        await writer.WriteLineAsync(data);
    }

    public async virtual Task<string> Receive()
    {
        return await reader.ReadLineAsync();
    }

}
}
问题是,当我试图将NetworkClient强制转换为SkyfilterClient时。引发异常,无法将“Network.NetworkClient”类型的对象强制转换为“Network.SkyfilterClient”类型


我的代码怎么了?我看到这个流可以转换成NetworkStream,MemoryStream。为什么NetworkClient不能转换为Skyfilter客户端?

在OOP中,不能将父类的实例强制转换为子类。只能将子实例强制转换为其继承自的父实例。

请使用强制转换运算符,如下所示:

var skyfilterClient = (SkyfilterClient)networkClient;

您不能
downcast
。如果创建了父对象,则无法将其强制转换为子对象

一个建议的解决方法是创建父级实现的
接口。如果需要,使用子覆盖功能,或者只公开父功能。将强制转换更改为接口并执行操作

编辑:也可以使用
is
关键字检查对象是否为
SkyfilterClient

   if(networkClient is SkyfilterClient)
   {

   }

只要对象实际上是一个
SkyfilterClient
,那么强制转换就可以工作。下面是一个人为的例子来证明这一点:

using System;

class Program
{
    static void Main()
    {
        NetworkClient net = new SkyfilterClient();
        var sky = (SkyfilterClient)net;
    }
}

public class NetworkClient{}
public class SkyfilterClient : NetworkClient{}
但是,如果它实际上是一个
NetworkClient
,那么您就无法神奇地使它成为子类。以下是一个例子:

using System;

class Program
{
    static void Main()
    {
        NetworkClient net = new NetworkClient();
        var sky = (SkyfilterClient)net;
    }
}

public class NetworkClient{}
public class SkyfilterClient : NetworkClient{}
但是,您可以创建一个转换器类。下面是一个例子,也是:

using System;

class Program
{
    static void Main()
    {
        NetworkClient net = new NetworkClient();
        var sky = SkyFilterClient.CopyToSkyfilterClient(net);
    }
}

public class NetworkClient
{  
  public int SomeVal {get;set;}
}

public class SkyfilterClient : NetworkClient
{
    public int NewSomeVal {get;set;}
    public static SkyfilterClient CopyToSkyfilterClient(NetworkClient networkClient)
    {
        return new SkyfilterClient{NewSomeVal = networkClient.SomeVal};
    }
}
但是,请记住,有一个原因,你不能转换这种方式。您可能缺少子类所需的关键信息

最后,如果您只想查看尝试的强制转换是否有效,则可以使用
is

if(client is SkyfilterClient)
    cast

可以将父类的值复制到子类。例如,如果是这种情况,您可以使用反射。

您可以使用as运算符在兼容的引用类型或可为空的类型之间执行某些类型的转换

SkyfilterClient c = client as SkyfilterClient;
if (c != null)
{
    //do something with it
}



NetworkClient c = new SkyfilterClient() as NetworkClient; // c is not null
SkyfilterClient c2 = new NetworkClient() as SkyfilterClient; // c2 is null

我很惊讶AutoMapper没有给出答案

从前面的所有答案中可以清楚地看出,您不能进行类型转换。但是,使用,在几行代码中,您可以基于现有的
NetworkClient
实例化一个新的
SkyfilterClient

本质上,您可以将以下内容放在当前正在进行打字的位置:

using AutoMapper;
...
// somewhere, your network client was declared
var existingNetworkClient = new NetworkClient();
...
// now we want to type-cast, but we can't, so we instantiate using AutoMapper
AutoMapper.Mapper.CreateMap<NetworkClient, SkyfilterClient>();
var skyfilterObject = AutoMapper.Mapper.Map<SkyfilterClient>(existingNetworkClient);
使用AutoMapper;
...
//在某个地方,您的网络客户端被声明
var existingNetworkClient=new NetworkClient();
...
//现在我们想要输入cast,但是我们不能,所以我们使用AutoMapper实例化
AutoMapper.Mapper.CreateMap();
var skyfilterObject=AutoMapper.Mapper.Map(现有NetworkClient);
下面是一个全面的例子:

  public class Vehicle
  {
    public int NumWheels { get; set; }
    public bool HasMotor { get; set; }
  }

  public class Car: Vehicle
  {
    public string Color { get; set; }
    public string SteeringColumnStyle { get; set; }
  }

  public class CarMaker
  {
    // I am given vehicles that I want to turn into cars...
    public List<Car> Convert(List<Vehicle> vehicles)
    {
      var cars = new List<Car>();
      AutoMapper.Mapper.CreateMap<Vehicle, Car>(); // Declare that we want some automagic to happen
      foreach (var vehicle in vehicles)
      {
        var car = AutoMapper.Mapper.Map<Car>(vehicle);
        // At this point, the car-specific properties (Color and SteeringColumnStyle) are null, because there are no properties in the Vehicle object to map from.
        // However, car's NumWheels and HasMotor properties which exist due to inheritance, are populated by AutoMapper.
        cars.Add(car);
      }
      return cars;
    }
  }
公共级车辆
{
public int NumWheels{get;set;}
公共布尔值{get;set;}
}
公营车辆
{
公共字符串颜色{get;set;}
公共字符串SteeringColumnStyle{get;set;}
}
公营汽车制造商
{
//我得到了想要变成汽车的车辆。。。
公共列表转换(列表车辆)
{
var cars=新列表();
AutoMapper.Mapper.CreateMap();//声明我们希望发生一些automagic
foreach(车辆中的var车辆)
{
var car=自动映射器映射器映射(车辆);
//此时,特定于车辆的属性(颜色和SteeringColumnStyle)为空,因为车辆对象中没有要从中映射的属性。
//然而,由于继承而存在的汽车NumWheels和HasMotor属性由AutoMapper填充。
cars.Add(car);
}
返回车辆;
}
}

我建议您从任何子类中识别所需的功能,并创建一个通用方法来转换到正确的子类中

我也有同样的问题,但我真的不想创建一些映射类或导入库

假设您需要“Authenticate”方法从正确的子类获取行为。在NetworkClient中:

protected bool Authenticate(string username, string password) {
  //...
}
protected bool DoAuthenticate<T>(NetworkClient nc, string username, string password) where T : NetworkClient {
//Do a cast into the sub class.
  T subInst = (T) nc;
  return nc.Authenticate(username, password);
}
受保护的bool身份验证(字符串用户名、字符串密码){
//...
}
受保护的bool DoAuthenticate(NetworkClient nc、字符串用户名、字符串密码),其中T:NetworkClient{
//在子类中进行转换。
T subInst=(T)nc;
返回nc.Authenticate(用户名、密码);
}

如果必须,而且您不介意黑客攻击,您可以让序列化为您完成这项工作

鉴于这些类别:

public class ParentObj
{
    public string Name { get; set; }
}

public class ChildObj : ParentObj
{
    public string Value { get; set; }
}
可以从父实例创建子实例,如下所示:

var parent = new ParentObj() { Name = "something" };
var serialized = JsonConvert.SerializeObject(parent);
var child = JsonConvert.DeserializeObject<ChildObj>(serialized);
var parent=newparentobj(){Name=“something”};
var serialized=JsonConvert.serialized对象(父对象);
var child=JsonConvert.DeserializeObject(序列化);
这假设您的对象可以很好地进行序列化,obv


请注意,这可能会比显式转换器慢。

有几种方法可以做到这一点。然而,这里有一个最简单的方法可以做到这一点,而且它是可重用的

发生的事情是,我们正在获取父类的所有属性,并更新子类上的相同属性。其中baseObj是父对象,T是子类

public static T ConvertToDerived<T>(object baseObj) where T : new()
    {
        var derivedObj = new T();
        var members = baseObj.GetType().GetMembers();
        foreach (var member in members)
        {
            object val = null;
            if (member.MemberType == MemberTypes.Field)
            {
                val = ((FieldInfo)member).GetValue(baseObj);
                ((FieldInfo)member).SetValue(derivedObj, val);
            }
            else if (member.MemberType == MemberTypes.Property)
            {
                val = ((PropertyInfo)member).GetValue(baseObj);
                if (val is IList && val.GetType().IsGenericType)
                {
                    var listType = val.GetType().GetGenericArguments().Single();
                    var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(listType));
                    foreach (var item in (IList)val)
                    {
                        list.Add(item);
                    }
                    ((PropertyInfo)member).SetValue(baseObj, list, null);
                }
                if (((PropertyInfo)member).CanWrite)
                    ((PropertyInfo)member).SetValue(derivedObj, val);
            }
        }
        return derivedObj;
    }
publicstatict ConvertToDerived(objectbaseobj),其中T:new()
{
var derivedObj=新的T();
var members=baseObj.GetType().GetMembers();
foreach(成员中的var成员)
{
对象val=null;
if(member.MemberType==MemberTypes.Field)
{
val=((FieldInfo)成员).GetValue(baseObj);
((FieldInfo)成员).SetValue(derivedObj,val);
}
else if(member.MemberType==MemberTypes.Property)
{
val=((PropertyInfo)成员).GetValue(baseObj);
if(val为IList&&val.GetType().IsGenericType)
{
var listType=val.GetType().GetGenericArguments().Single();
变量列表=(IList)Act
public static T ConvertToDerived<T>(object baseObj) where T : new()
    {
        var derivedObj = new T();
        var members = baseObj.GetType().GetMembers();
        foreach (var member in members)
        {
            object val = null;
            if (member.MemberType == MemberTypes.Field)
            {
                val = ((FieldInfo)member).GetValue(baseObj);
                ((FieldInfo)member).SetValue(derivedObj, val);
            }
            else if (member.MemberType == MemberTypes.Property)
            {
                val = ((PropertyInfo)member).GetValue(baseObj);
                if (val is IList && val.GetType().IsGenericType)
                {
                    var listType = val.GetType().GetGenericArguments().Single();
                    var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(listType));
                    foreach (var item in (IList)val)
                    {
                        list.Add(item);
                    }
                    ((PropertyInfo)member).SetValue(baseObj, list, null);
                }
                if (((PropertyInfo)member).CanWrite)
                    ((PropertyInfo)member).SetValue(derivedObj, val);
            }
        }
        return derivedObj;
    }
public static string ConvertToJson<T>(this T obj)
{
    return JsonConvert.SerializeObject(obj);
}
public static T ConvertToObject<T>(this string json)
{
    if (string.IsNullOrEmpty(json))
    {
        return Activator.CreateInstance<T>();
    }
    return JsonConvert.DeserializeObject<T>(json);
}
var sfcl = networkClient.ConvertToJson().ConvertToObject<SkyfilterClient>();