是否有可能分配基类对象的一个源类参与的一个明确的定型C#?.

我已经尝试过了,它创建了一个运行时的错误。

有帮助吗?

解决方案

没有。派生类的引用必须实际指派生类(或空)的实例。否则你将如何指望它的行为?

例如:

object o = new object();
string s = (string) o;
int i = s.Length; // What can this sensibly do?

如果您希望能够对基本类型的实例转换为派生类型,我建议你写来创建相应的派生类型实例的方法。或者看看你的继承树再次尝试重新设计,这样你就不需要做这个摆在首位。

其他提示

没有,这不是因为它分配给派生类引用可能会是这样说:“基类是派生类完全有能力替代品,它可以做的一切派生类可以做”,这是不正确的,因为派生类一般提供更多的功能比它们的基类(至少,这就是后面继承的想法)。

您可以写在派生类的构造函数取一个基类对象作为参数,将值复制。

像这样:

public class Base {
    public int Data;

    public void DoStuff() {
        // Do stuff with data
    }
}

public class Derived : Base {
    public int OtherData;

    public Derived(Base b) {
        this.Data = b.Data;
        OtherData = 0; // default value
    }

    public void DoOtherStuff() {
        // Do some other stuff
    }
}

在这种情况下,应复制的基础对象,并得到一个完整功能的派生类对象具有用于派生成员的默认值。这种方式,您也可避免这个问题所指出的乔恩斯基特:

Base b = new Base();
Dervided d = new Derived();

b.DoStuff();    // OK
d.DoStuff();    // Also OK
b.DoOtherStuff();    // Won't work!
d.DoOtherStuff();    // OK

d = new Derived(b);  // Copy construct a Derived with values of b
d.DoOtherStuff();    // Now works!

我有这个问题,通过增加需要一个类型参数和转换当前对象到该类型的方法解决了这个问题。

public TA As<TA>() where TA : Base
{
    var type = typeof (TA);
    var instance = Activator.CreateInstance(type);

     PropertyInfo[] properties = type.GetProperties();
     foreach (var property in properties)
     {
         property.SetValue(instance, property.GetValue(this, null), null);
     }

     return (TA)instance;
}

这意味着你可以在你这样的代码使用它:

var base = new Base();
base.Data = 1;
var derived = base.As<Derived>();
Console.Write(derived.Data); // Would output 1

由于许多人都回答说,不是。

我使用那些不幸的场合下面的代码,当我需要使用一个基本类型当作派生类型。是的,它是违反了里氏替换原则(LSP)是的大部分时间,我们倾向于在组成继承。道具马库斯Knappen约翰森其原来的答案,这是基于

这个代码在基类:

    public T As<T>()
    {
        var type = typeof(T);
        var instance = Activator.CreateInstance(type);

        if (type.BaseType != null)
        {
            var properties = type.BaseType.GetProperties();
            foreach (var property in properties)
                if (property.CanWrite)
                    property.SetValue(instance, property.GetValue(this, null), null);
        }

        return (T) instance;
    }

允许:

    derivedObject = baseObect.As<derivedType>()

由于它使用反射,它是“贵”。相应地使用。

没有这是不可能的,因此你的运行时错误。

但是,可以将派生类的实例分配给基类类型的的变量。

由于这里的每个人说,这是不可能的直接。

我喜欢和是相当清洁的方法,是使用如 AutoMapper 对象映射器。

,它会自动做复制属性的任务从一个实例到另一个(不一定是同一类型)。

可以投下的可变其被分类为基类派生类的类型;然而,必然这会做运行时检查,以确定所涉及的实际对象是正确的类型。

一旦创建,的对象的不能被改变(未至少,它可能不是相同的尺寸)。你可以,但是,的转换的一个实例,创建一个第二类的实例 - 但你需要手动编写转换代码

扩大对@ YBO的答案 - 因为你有基类的实例实际上不是派生类的一个实例,它是不可能的。它仅知道的基类的成员,并且不知道这些派生类的任何东西。

这可以投派生类的实例,以基类的一个实例,其原因是因为派生类实际上已经是基类的一个实例,由于其具有的那些成员已经。相反,不能说。

没有,这是不可能的。

考虑一个情形,其中一个是ACBus派生类基类的总线。 ACBus有一个像TurnOnAC和TurnOffAC特征,其上一个名为ACState场工作。 TurnOnAC设置ACState就和TurnOffAC设置ACState关闭。如果您尝试使用公交TurnOnAC和TurnOffAC特点,它是没有意义的。

class Program
{
    static void Main(string[] args)
    {
        a a1 = new b();  
        a1.print();  
    }
}
class a
{
    public a()
    {
        Console.WriteLine("base class object initiated");
    }
    public void print()
    {
        Console.WriteLine("base");
    }
}
class b:a
{
    public b()
    {
        Console.WriteLine("child class object");
    }
    public void print1()
    {
        Console.WriteLine("derived");
    }
}

}

当我们创建子类对象,基类对象是发起所以基类引用变量auto可以指向子类对象。

而不是相反,因为因为没有创建子类对象的子类引用变量不能指向基类对象。

和还会注意到基类引用变量只能调用基类的成员。

实际上有办法这样做。想想你可能会使用Newtonsoft计deserialize一个对象从手机中。它将(或至少能)忽视缺少的元素,并填写所有要素,它不知道。

所以这里就是我如何做它。一个小小的代码样本将按照我的解释。

  1. 创建一个实例的对象从基类和填充。

  2. 使用"jsonconvert"类Newtonsoft式,serialize,对象为json串。

  3. 现在为你的子类目,通过反序列化与id string创建中的步骤2。这将创建一个实例子类的所有特性的基类。

这就像一个魅力!所以..当这有用吗?一些人询问,当这个会有意义和建议改变作的架构,以适应事实上,你本身无法做到这类继承(。网)。

在我的情况下,我有一个的设置类,包含所有的"基地"设置服务。具体服务有更多的选择和那些来自不同的数据表,所以这些类继承的基类。他们都有不同的选项。因此,当检索数据的服务,就更容易第一次填充的价值使用的一个实例基础对象。一种方法来这样做与一个单一数据库查询。那之后,我创造的子类目的使用方法概述的以上。然后我做的第二个查询和填写所有的动态价值的分类对象。

最后产出的是一个源类与所有选项的设定。重复这种对于附加新的分类只需要几代码行。这是简单的,以及它使用非常尝试和测试的软件包(Newtonsoft)使魔法的工作。

这个例子码是vb.Net但你可以很容易地转换为。

' First, create the base settings object.
    Dim basePMSettngs As gtmaPayMethodSettings = gtmaPayments.getBasePayMethodSetting(payTypeId, account_id)
    Dim basePMSettingsJson As String = JsonConvert.SerializeObject(basePMSettngs, Formatting.Indented)

    ' Create a pmSettings object of this specific type of payment and inherit from the base class object
    Dim pmSettings As gtmaPayMethodAimACHSettings = JsonConvert.DeserializeObject(Of gtmaPayMethodAimACHSettings)(basePMSettingsJson)

可能不是培训相关,但我能够赋予其基部的派生对象上运行的代码。这是肯定更哈克比我想的,但它的工作原理:

public static T Cast<T>(object obj)
{
    return (T)obj;
}

...

//Invoke parent object's json function
MethodInfo castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(baseObj.GetType());
object castedObject = castMethod.Invoke(null, new object[] { baseObj });
MethodInfo jsonMethod = baseObj.GetType ().GetMethod ("ToJSON");
return (string)jsonMethod.Invoke (castedObject,null);

可以使用延伸:

public static void CopyOnlyEqualProperties<T>(this T objDest, object objSource) where T : class
    {
        foreach (PropertyInfo propInfo in typeof(T).GetProperties())
            if (objSource.GetType().GetProperties().Any(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()))
                propInfo.SetValue(objDest, objSource.GetType().GetProperties().First(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()).GetValue(objSource));
    }

在编码:

public class BaseClass
{
  public string test{ get; set;}
}
public Derived : BaseClass
{
//Some properies
}

public void CopyProps()
{
   BaseClass baseCl =new BaseClass();
   baseCl.test="Hello";
   Derived drv=new Derived();
   drv.CopyOnlyEqualProperties(baseCl);
   //Should return Hello to the console now in derived class.
   Console.WriteLine(drv.test);

}

我知道这是旧的,但我已经成功地使用这个相当长一段时间。

   private void PopulateDerivedFromBase<TB,TD>(TB baseclass,TD derivedclass)
    {
        //get our baseclass properties
        var bprops = baseclass.GetType().GetProperties();
        foreach (var bprop in bprops)
        {
            //get the corresponding property in the derived class
            var dprop = derivedclass.GetType().GetProperty(bprop.Name);
            //if the derived property exists and it's writable, set the value
            if (dprop != null && dprop.CanWrite)
                dprop.SetValue(derivedclass,bprop.GetValue(baseclass, null),null);
        }
    } 

与JsonConvert(而不是类型转换)溶液

今天,我面临着同样的问题,我发现一种简单和快速解决问题的方法使用JsonConvert

var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);

另一种解决方案是增加扩展方法,像这样:

 public static void CopyProperties(this object destinationObject, object sourceObject, bool overwriteAll = true)
        {
            try
            {
                if (sourceObject != null)
                {
                    PropertyInfo[] sourceProps = sourceObject.GetType().GetProperties();
                    List<string> sourcePropNames = sourceProps.Select(p => p.Name).ToList();
                    foreach (PropertyInfo pi in destinationObject.GetType().GetProperties())
                    {
                        if (sourcePropNames.Contains(pi.Name))
                        {
                            PropertyInfo sourceProp = sourceProps.First(srcProp => srcProp.Name == pi.Name);
                            if (sourceProp.PropertyType == pi.PropertyType)
                                if (overwriteAll || pi.GetValue(destinationObject, null) == null)
                                {
                                    pi.SetValue(destinationObject, sourceProp.GetValue(sourceObject, null), null);
                                }
                        }
                    }
                }
            }
            catch (ApplicationException ex)
            {
                throw;
            }
        }

然后在每个派生类接受基类的构造:

  public class DerivedClass: BaseClass
    { 
        public DerivedClass(BaseClass baseModel)
        {
            this.CopyProperties(baseModel);
        }
    }

如果已经设置(不为空),或不还将任选地覆盖目标属性。

  

是否有可能基类对象分配给一个派生类参考在C#?

的显式类型转换

不仅明确的,而且也隐式转换是可能的。

C#语言不允许这样的转换操作符,但你仍然可以使用纯C#写他们和他们的工作。需要注意的是它定义了隐式转换运算符(Derived)及使用该运营商(Program)的类的类必须在单独的组件来定义(例如,Derived类是在由含有library.dllprogram.exe引用的Program)。

//In library.dll:
public class Base { }

public class Derived {
    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Implicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }

    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Explicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }
}

//In program.exe:
class Program {
    static void Main(string[] args) {
        Derived z = new Base(); //Visual Studio can show squiggles here, but it compiles just fine.
    }
}

当您参考使用Visual Studio中的项目参考图书馆,VS显示波浪线当您使用隐式转换,但它编译就好了。如果你只是引用library.dll,没有波浪线。

你可以这样做使用通用的。

public class BaseClass
{
    public int A { get; set; }
    public int B { get; set; }
    private T ConvertTo<T>() where T : BaseClass, new()
    {
         return new T
         {
             A = A,
             B = B
         }
    }

    public DerivedClass1 ConvertToDerivedClass1()
    {
         return ConvertTo<DerivedClass1>();
    }

    public DerivedClass2 ConvertToDerivedClass2()
    {
         return ConvertTo<DerivedClass2>();
    }
}

public class DerivedClass1 : BaseClass
{
    public int C { get; set; }
}

public class DerivedClass2 : BaseClass
{
    public int D { get; set; }
}

你三个好处使用这种方法。

  1. 你是不是重复代码
  2. 你是不是利用反射(其缓慢)
  3. 所有的你的转换都是在一个地方

我相结合的某些部分的先前答复(感谢那些作者),把一个简单的静态级有两个方法,我们使用。

是的,这很简单,没有这并不复盖所有情况,是的,它可以扩大并取得更好,不,它不是完美的,是的,它可能可以提高效率,没有这不是最伟大的事情,因为片面包,是有全面强大的nuget对象映射器,方式更好地为大量使用,等等,亚达亚达--但它的工作原理我们的基本需求虽然:)

当然,它会尝试图价值观任何反对任何目的,衍生或没有(只有公共性质的命名的相同的课程--忽略了其余).

使用:

SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };

// creates new object of type "RealPerson" and assigns any matching property 
// values from the puppet object 
// (this method requires that "RealPerson" have a parameterless constructor )
RealPerson person = ObjectMapper.MapToNewObject<RealPerson>(puppet);

// OR

// create the person object on our own 
// (so RealPerson can have any constructor type that it wants)
SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };
RealPerson person = new RealPerson("tall") {Name = "Steve"};

// maps and overwrites any matching property values from 
// the puppet object to the person object so now our person's age will get set to 5 and
// the name "Steve" will get overwritten with "Elmo" in this example
ObjectMapper.MapToExistingObject(puppet, person);

静态工具类:

public static class ObjectMapper
{
    // the target object is created on the fly and the target type 
    // must have a parameterless constructor (either compiler-generated or explicit) 
    public static Ttarget MapToNewObject<Ttarget>(object sourceobject) where Ttarget : new()
    {
        // create an instance of the target class
        Ttarget targetobject = (Ttarget)Activator.CreateInstance(typeof(Ttarget));

        // map the source properties to the target object
        MapToExistingObject(sourceobject, targetobject);

        return targetobject;
    }

    // the target object is created beforehand and passed in
    public static void MapToExistingObject(object sourceobject, object targetobject)
    {
        // get the list of properties available in source class
        var sourceproperties = sourceobject.GetType().GetProperties().ToList();

        // loop through source object properties
        sourceproperties.ForEach(sourceproperty => {

            var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);

            // check whether that property is present in target class and is writeable
            if (targetProp != null && targetProp.CanWrite)
            {
                // if present get the value and map it
                var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
                targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
            }
        });
    }
}

如何:

public static T As<T>(this object obj)
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
    }

要所有基地属性添加到导出的项最好的办法是在costructor使用反射。尝试这种代码,而无需创建方法或实例。

    public Derived(Base item) :base()
    {

        Type type = item.GetType();

        System.Reflection.PropertyInfo[] properties = type.GetProperties();
        foreach (var property in properties)
        {
            try
            {
                property.SetValue(this, property.GetValue(item, null), null);
            }
            catch (Exception) { }
        }

    }

我不同意,这是不可能的。你可以做这样的:

public class Auto 
{ 
    public string Make {get; set;}
    public string Model {get; set;}
}

public class Sedan : Auto
{ 
    public int NumberOfDoors {get; set;}
}

public static T ConvertAuto<T>(Sedan sedan) where T : class
{
    object auto = sedan;
    return (T)loc;
}

用法:

var sedan = new Sedan();
sedan.NumberOfDoors = 4;
var auto = ConvertAuto<Auto>(sedan);

没有,看到这个问题,我问 - 使用泛型上溯造型在.NET

,最好的方法是使在类一个默认的构造,构造,然后调用一个方法Initialise

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top