是否可以将基类对象分配给带有显式类型播的派生类引用?

时间:2023-01-15 20:55:44

Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?.

是否可以使用c#中的显式类型ast将基类对象分配给派生类引用?

I have tried it and it creates a run-time error.

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

17 个解决方案

#1


75  

No. A reference to a derived class must actually refer to an instance of the derived class (or null). Otherwise how would you expect it to behave?

不。对派生类的引用实际上必须引用派生类的实例(或null)。否则你会期望它如何表现?

For example:

例如:

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

If you want to be able to convert an instance of the base type to the derived type, I suggest you write a method to create an appropriate derived type instance. Or look at your inheritance tree again and try to redesign so that you don't need to do this in the first place.

如果您希望能够将基类型的实例转换为派生类型,我建议您编写一个方法来创建适当的派生类型实例。或者再看一遍你的继承树然后重新设计这样你就不需要一开始就这么做了。

#2


37  

No, that's not possible since assigning it to a derived class reference would be like saying "Base class is a fully capable substitute for derived class, it can do everything the derived class can do", which is not true since derived classes in general offer more functionality than their base class (at least, that's the idea behind inheritance).

不,那是不可能的因为分配到一个派生类引用就像是说“基类是完全能够替代派生类,它可以做所有派生类可以做”,这是不对的,因为一般的派生类提供更多的功能比基类(至少,这是继承)背后的想法。

You could write a constructor in the derived class taking a base class object as parameter, copying the values.

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

Something like this:

是这样的:

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

In that case you would copy the base object and get a fully functional derived class object with default values for derived members. This way you can also avoid the problem pointed out by Jon Skeet:

在这种情况下,您将复制基本对象并获得一个具有派生成员默认值的完全功能派生类对象。这样你也可以避免Jon Skeet指出的问题:

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!

#3


15  

I had this problem and solved it by adding a method that takes a type parameter and converts the current object into that type.

我遇到了这个问题,并通过添加一个方法来解决它,该方法接受类型参数并将当前对象转换为该类型。

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

That means that you can use it in you code like this:

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

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

#4


7  

As many others have answered, No.

正如许多人回答的那样,没有。

I use the following code on those unfortunate occasions when I need to use a base type as a derived type. Yes it is a violation of the Liskov Substitution Principle (LSP) and yes most of the time we favor composition over inheritance. Props to Markus Knappen Johansson whose original answer this is based upon.

当需要使用基类型作为派生类型时,我将使用以下代码。是的,这违反了Liskov替换原则(LSP),而且大多数时候我们更喜欢组合而不是继承。感谢马库斯·克纳彭·约翰逊,他的原话是基于他的原话。

This code in the base class:

基类中的此代码:

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

Allows:

允许:

    derivedObject = baseObect.As<derivedType>()

Since it uses reflection, it is "expensive". Use accordingly.

因为它使用反射,所以它是“昂贵的”。相应的使用。

#5


5  

No it is not possible, hence your runtime error.

不,这是不可能的,因此您的运行时错误。

But you can assign an instance of a derived class to a variable of base class type.

但您可以将派生类的实例赋给基类类型的变量。

#6


3  

You can cast a variable that is typed as the base-class to the type of a derived class; however, by necessity this will do a runtime check, to see if the actual object involved is of the correct type.

可以将类型化为基类的变量转换为派生类的类型;然而,出于必要,它将进行运行时检查,以查看所涉及的实际对象是否具有正确的类型。

Once created, the type of an object cannot be changed (not least, it might not be the same size). You can, however, convert an instance, creating a new instance of the second type - but you need to write the conversion code manually.

一旦创建,对象的类型就不能更改(尤其是,它可能不是相同的大小)。但是,您可以转换一个实例,创建第二个类型的新实例——但是您需要手动编写转换代码。

#7


3  

As everyone here said, that's not possible directly.

正如这里的每个人所说,这是不可能直接实现的。

The method I prefer and is rather clean, is to use an Object Mapper like AutoMapper.

我比较喜欢并且比较干净的方法是使用像AutoMapper这样的对象映射器。

It will do the task of copying properties from one instance to another (Not necessarily the same type) automatically.

它将自动将属性从一个实例复制到另一个实例(不一定是相同的类型)。

#8


2  

Expanding on @ybo's answer - it isn't possible because the instance you have of the base class isn't actually an instance of the derived class. It only knows about the members of the base class, and doesn't know anything about those of the derived class.

扩展@ybo的答案——这不可能,因为基类的实例实际上不是派生类的实例。它只知道基类的成员,并且不知道关于派生类的任何内容。

The reason that you can cast an instance of the derived class to an instance of the base class is because the derived class actually already is an instance of the base class, since it has those members already. The opposite cannot be said.

之所以可以将派生类的实例强制转换为基类的实例,是因为派生类实际上已经是基类的实例,因为它已经拥有这些成员。相反的情况是不能说的。

#9


2  

No, it is not possible.

不,这是不可能的。

Consider a scenario where an ACBus is a derived class of base class Bus. ACBus has features like TurnOnAC and TurnOffAC which operate on a field named ACState. TurnOnAC sets ACState to on and TurnOffAC sets ACState to off. If you try to use TurnOnAC and TurnOffAC features on Bus, it makes no sense.

考虑这样一个场景:ACBus是基类总线的派生类。ACBus具有TurnOnAC和ffac等特性,它们在一个名为ACState的字段上运行。TurnOnAC将ACState设置为on,并将ACState设置为off。如果你尝试在总线上使用TurnOnAC和ffac特性,这是毫无意义的。

#10


2  

There actually IS a way to do this. Think about how you might use Newtonsoft JSON to deserialize an object from json. It will (or at least can) ignore missing elements and populate all the elements that it does know about.

实际上有一种方法可以做到这一点。考虑一下如何使用Newtonsoft JSON从JSON中反序列化一个对象。它将(或至少可以)忽略丢失的元素并填充它所知道的所有元素。

So here's how I did it. A small code sample will follow my explanation.

我是这么做的。下面是一个小的代码示例。

  1. Create an instance of your object from the base class and populate it accordingly.

    从基类创建一个对象实例,并相应地填充它。

  2. Using the "jsonconvert" class of Newtonsoft json, serialize that object into a json string.

    使用Newtonsoft json的“jsonconvert”类,将该对象序列化为json字符串。

  3. Now create your sub class object by deserializing with the json string created in step 2. This will create an instance of your sub class with all the properties of the base class.

    现在通过反序列化步骤2中创建的json字符串来创建子类对象。这将创建一个包含基类所有属性的子类的实例。

This works like a charm! So.. when is this useful? Some people asked when this would make sense and suggested changing the OP's schema to accommodate the fact that you can't natively do this with class inheritance (in .Net).

这很有魅力!所以. .当这是有用的吗?有些人问这什么时候才有意义,并建议修改OP的模式,以适应您不能使用类继承(在. net中)来实现这一点。

In my case, I have a settings class that contains all the "base" settings for a service. Specific services have more options and those come from a different DB table, so those classes inherit the base class. They all have a different set of options. So when retrieving the data for a service, it's much easier to FIRST populate the values using an instance of the base object. One method to do this with a single DB query. Right after that, I create the sub class object using the method outlined above. I then make a second query and populate all the dynamic values on the sub class object.

在我的例子中,我有一个settings类包含一个服务的所有“base”设置。特定的服务有更多的选项,这些选项来自不同的DB表,因此这些类继承了基类。他们都有不同的选择。因此,当检索服务的数据时,首先使用基对象的实例填充值要容易得多。使用一个DB查询实现此目的的方法。之后,我使用上面列出的方法创建子类对象。然后,我进行第二个查询,并填充子类对象上的所有动态值。

The final output is a derived class with all the options set. Repeating this for additional new sub classes takes just a few lines of code. It's simple, and it uses a very tried and tested package (Newtonsoft) to make the magic work.

最后的输出是一个包含所有选项的派生类。对于其他的子类,重复这个操作只需要几行代码。它很简单,并且它使用了一个非常经过测试的软件包(Newtonsoft)来实现这个神奇的工作。

This example code is vb.Net, but you can easily convert to c#.

这个示例代码是vb。Net,但是可以很容易地转换为c#。

' 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)

#11


1  

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

}

}

when we create a child class object,the base class object is auto initiated so base class reference variable can point to child class object.

当我们创建子类对象时,基类对象是自动启动的,因此基类引用变量可以指向子类对象。

but not vice versa because a child class reference variable can not point to base class object because no child class object is created.

反之亦然,因为子类引用变量不能指向基类对象,因为没有创建子类对象。

and also notice that base class reference variable can only call base class member.

还要注意,基类引用变量只能调用基类成员。

#12


0  

Another solution is to add extension method like so:

另一种解决方案是增加可拓方法如下:

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

then have a constructor in each derived class that accepts base class:

然后在每个派生类中都有一个接受基类的构造函数:

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

It will also optionally overwrite destination properties if already set (not null) or not.

如果已经设置(非空)或没有设置,也可以选择覆盖目标属性。

#13


0  

Might not be relevent, but I was able to run code on a derived object given its base. It's definitely more hacky than I'd like, but it works:

可能不相关,但是我能够在给定基的派生对象上运行代码。这绝对比我想要的更陈腐,但它确实有效:

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

#14


0  

Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?.

是否可以使用c#中的显式类型ast将基类对象分配给派生类引用?

Not only explicit, but also implicit conversions are possible.

不仅可以显式转换,还可以隐式转换。

C# language doesn't permit such conversion operators, but you can still write them using pure C# and they work. Note that the class which defines the implicit conversion operator (Derived) and the class which uses the operator (Program) must be defined in separate assemblies (e.g. the Derived class is in a library.dll which is referenced by program.exe containing the Program class).

c#语言不允许这样的转换操作符,但是您仍然可以使用纯c#编写它们,并且它们可以工作。注意,定义隐式转换运算符(派生)的类和使用运算符(程序)的类必须在单独的程序集中定义(例如,派生类在库中)。程序引用的dll。包含程序类的exe。

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

When you reference the library using the Project Reference in Visual Studio, VS shows squiggles when you use the implicit conversion, but it compiles just fine. If you just reference the library.dll, there are no squiggles.

当您在Visual Studio中使用项目引用引用库时,VS在使用隐式转换时显示了squiggles,但是它编译得很好。如果你只是参考图书馆的话。dll,没有弯弯曲曲的。

#15


0  

You can do this using generic.

您可以使用泛型实现这一点。

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

You get three benefits using this approach.

使用这种方法可以获得三个好处。

  1. You are not duplicating the code
  2. 您没有复制代码
  3. You are not using reflection (which is slow)
  4. 你没有使用反射(反射很慢)
  5. All of your conversions are in one place
  6. 所有的转换都在一个地方。

#16


0  

You can use an Extention:

你可以使用扩展:

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

In Code:

在代码:

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

}

#17


-1  

No, see this question which I asked - Upcasting in .NET using generics

不,看看我问的这个问题-在。net中使用泛型

The best way is to make a default constructor on the class, construct and then call an Initialise method

最好的方法是在类上创建一个默认构造函数,构造并调用初始化方法

#1


75  

No. A reference to a derived class must actually refer to an instance of the derived class (or null). Otherwise how would you expect it to behave?

不。对派生类的引用实际上必须引用派生类的实例(或null)。否则你会期望它如何表现?

For example:

例如:

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

If you want to be able to convert an instance of the base type to the derived type, I suggest you write a method to create an appropriate derived type instance. Or look at your inheritance tree again and try to redesign so that you don't need to do this in the first place.

如果您希望能够将基类型的实例转换为派生类型,我建议您编写一个方法来创建适当的派生类型实例。或者再看一遍你的继承树然后重新设计这样你就不需要一开始就这么做了。

#2


37  

No, that's not possible since assigning it to a derived class reference would be like saying "Base class is a fully capable substitute for derived class, it can do everything the derived class can do", which is not true since derived classes in general offer more functionality than their base class (at least, that's the idea behind inheritance).

不,那是不可能的因为分配到一个派生类引用就像是说“基类是完全能够替代派生类,它可以做所有派生类可以做”,这是不对的,因为一般的派生类提供更多的功能比基类(至少,这是继承)背后的想法。

You could write a constructor in the derived class taking a base class object as parameter, copying the values.

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

Something like this:

是这样的:

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

In that case you would copy the base object and get a fully functional derived class object with default values for derived members. This way you can also avoid the problem pointed out by Jon Skeet:

在这种情况下,您将复制基本对象并获得一个具有派生成员默认值的完全功能派生类对象。这样你也可以避免Jon Skeet指出的问题:

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!

#3


15  

I had this problem and solved it by adding a method that takes a type parameter and converts the current object into that type.

我遇到了这个问题,并通过添加一个方法来解决它,该方法接受类型参数并将当前对象转换为该类型。

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

That means that you can use it in you code like this:

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

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

#4


7  

As many others have answered, No.

正如许多人回答的那样,没有。

I use the following code on those unfortunate occasions when I need to use a base type as a derived type. Yes it is a violation of the Liskov Substitution Principle (LSP) and yes most of the time we favor composition over inheritance. Props to Markus Knappen Johansson whose original answer this is based upon.

当需要使用基类型作为派生类型时,我将使用以下代码。是的,这违反了Liskov替换原则(LSP),而且大多数时候我们更喜欢组合而不是继承。感谢马库斯·克纳彭·约翰逊,他的原话是基于他的原话。

This code in the base class:

基类中的此代码:

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

Allows:

允许:

    derivedObject = baseObect.As<derivedType>()

Since it uses reflection, it is "expensive". Use accordingly.

因为它使用反射,所以它是“昂贵的”。相应的使用。

#5


5  

No it is not possible, hence your runtime error.

不,这是不可能的,因此您的运行时错误。

But you can assign an instance of a derived class to a variable of base class type.

但您可以将派生类的实例赋给基类类型的变量。

#6


3  

You can cast a variable that is typed as the base-class to the type of a derived class; however, by necessity this will do a runtime check, to see if the actual object involved is of the correct type.

可以将类型化为基类的变量转换为派生类的类型;然而,出于必要,它将进行运行时检查,以查看所涉及的实际对象是否具有正确的类型。

Once created, the type of an object cannot be changed (not least, it might not be the same size). You can, however, convert an instance, creating a new instance of the second type - but you need to write the conversion code manually.

一旦创建,对象的类型就不能更改(尤其是,它可能不是相同的大小)。但是,您可以转换一个实例,创建第二个类型的新实例——但是您需要手动编写转换代码。

#7


3  

As everyone here said, that's not possible directly.

正如这里的每个人所说,这是不可能直接实现的。

The method I prefer and is rather clean, is to use an Object Mapper like AutoMapper.

我比较喜欢并且比较干净的方法是使用像AutoMapper这样的对象映射器。

It will do the task of copying properties from one instance to another (Not necessarily the same type) automatically.

它将自动将属性从一个实例复制到另一个实例(不一定是相同的类型)。

#8


2  

Expanding on @ybo's answer - it isn't possible because the instance you have of the base class isn't actually an instance of the derived class. It only knows about the members of the base class, and doesn't know anything about those of the derived class.

扩展@ybo的答案——这不可能,因为基类的实例实际上不是派生类的实例。它只知道基类的成员,并且不知道关于派生类的任何内容。

The reason that you can cast an instance of the derived class to an instance of the base class is because the derived class actually already is an instance of the base class, since it has those members already. The opposite cannot be said.

之所以可以将派生类的实例强制转换为基类的实例,是因为派生类实际上已经是基类的实例,因为它已经拥有这些成员。相反的情况是不能说的。

#9


2  

No, it is not possible.

不,这是不可能的。

Consider a scenario where an ACBus is a derived class of base class Bus. ACBus has features like TurnOnAC and TurnOffAC which operate on a field named ACState. TurnOnAC sets ACState to on and TurnOffAC sets ACState to off. If you try to use TurnOnAC and TurnOffAC features on Bus, it makes no sense.

考虑这样一个场景:ACBus是基类总线的派生类。ACBus具有TurnOnAC和ffac等特性,它们在一个名为ACState的字段上运行。TurnOnAC将ACState设置为on,并将ACState设置为off。如果你尝试在总线上使用TurnOnAC和ffac特性,这是毫无意义的。

#10


2  

There actually IS a way to do this. Think about how you might use Newtonsoft JSON to deserialize an object from json. It will (or at least can) ignore missing elements and populate all the elements that it does know about.

实际上有一种方法可以做到这一点。考虑一下如何使用Newtonsoft JSON从JSON中反序列化一个对象。它将(或至少可以)忽略丢失的元素并填充它所知道的所有元素。

So here's how I did it. A small code sample will follow my explanation.

我是这么做的。下面是一个小的代码示例。

  1. Create an instance of your object from the base class and populate it accordingly.

    从基类创建一个对象实例,并相应地填充它。

  2. Using the "jsonconvert" class of Newtonsoft json, serialize that object into a json string.

    使用Newtonsoft json的“jsonconvert”类,将该对象序列化为json字符串。

  3. Now create your sub class object by deserializing with the json string created in step 2. This will create an instance of your sub class with all the properties of the base class.

    现在通过反序列化步骤2中创建的json字符串来创建子类对象。这将创建一个包含基类所有属性的子类的实例。

This works like a charm! So.. when is this useful? Some people asked when this would make sense and suggested changing the OP's schema to accommodate the fact that you can't natively do this with class inheritance (in .Net).

这很有魅力!所以. .当这是有用的吗?有些人问这什么时候才有意义,并建议修改OP的模式,以适应您不能使用类继承(在. net中)来实现这一点。

In my case, I have a settings class that contains all the "base" settings for a service. Specific services have more options and those come from a different DB table, so those classes inherit the base class. They all have a different set of options. So when retrieving the data for a service, it's much easier to FIRST populate the values using an instance of the base object. One method to do this with a single DB query. Right after that, I create the sub class object using the method outlined above. I then make a second query and populate all the dynamic values on the sub class object.

在我的例子中,我有一个settings类包含一个服务的所有“base”设置。特定的服务有更多的选项,这些选项来自不同的DB表,因此这些类继承了基类。他们都有不同的选择。因此,当检索服务的数据时,首先使用基对象的实例填充值要容易得多。使用一个DB查询实现此目的的方法。之后,我使用上面列出的方法创建子类对象。然后,我进行第二个查询,并填充子类对象上的所有动态值。

The final output is a derived class with all the options set. Repeating this for additional new sub classes takes just a few lines of code. It's simple, and it uses a very tried and tested package (Newtonsoft) to make the magic work.

最后的输出是一个包含所有选项的派生类。对于其他的子类,重复这个操作只需要几行代码。它很简单,并且它使用了一个非常经过测试的软件包(Newtonsoft)来实现这个神奇的工作。

This example code is vb.Net, but you can easily convert to c#.

这个示例代码是vb。Net,但是可以很容易地转换为c#。

' 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)

#11


1  

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

}

}

when we create a child class object,the base class object is auto initiated so base class reference variable can point to child class object.

当我们创建子类对象时,基类对象是自动启动的,因此基类引用变量可以指向子类对象。

but not vice versa because a child class reference variable can not point to base class object because no child class object is created.

反之亦然,因为子类引用变量不能指向基类对象,因为没有创建子类对象。

and also notice that base class reference variable can only call base class member.

还要注意,基类引用变量只能调用基类成员。

#12


0  

Another solution is to add extension method like so:

另一种解决方案是增加可拓方法如下:

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

then have a constructor in each derived class that accepts base class:

然后在每个派生类中都有一个接受基类的构造函数:

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

It will also optionally overwrite destination properties if already set (not null) or not.

如果已经设置(非空)或没有设置,也可以选择覆盖目标属性。

#13


0  

Might not be relevent, but I was able to run code on a derived object given its base. It's definitely more hacky than I'd like, but it works:

可能不相关,但是我能够在给定基的派生对象上运行代码。这绝对比我想要的更陈腐,但它确实有效:

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

#14


0  

Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?.

是否可以使用c#中的显式类型ast将基类对象分配给派生类引用?

Not only explicit, but also implicit conversions are possible.

不仅可以显式转换,还可以隐式转换。

C# language doesn't permit such conversion operators, but you can still write them using pure C# and they work. Note that the class which defines the implicit conversion operator (Derived) and the class which uses the operator (Program) must be defined in separate assemblies (e.g. the Derived class is in a library.dll which is referenced by program.exe containing the Program class).

c#语言不允许这样的转换操作符,但是您仍然可以使用纯c#编写它们,并且它们可以工作。注意,定义隐式转换运算符(派生)的类和使用运算符(程序)的类必须在单独的程序集中定义(例如,派生类在库中)。程序引用的dll。包含程序类的exe。

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

When you reference the library using the Project Reference in Visual Studio, VS shows squiggles when you use the implicit conversion, but it compiles just fine. If you just reference the library.dll, there are no squiggles.

当您在Visual Studio中使用项目引用引用库时,VS在使用隐式转换时显示了squiggles,但是它编译得很好。如果你只是参考图书馆的话。dll,没有弯弯曲曲的。

#15


0  

You can do this using generic.

您可以使用泛型实现这一点。

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

You get three benefits using this approach.

使用这种方法可以获得三个好处。

  1. You are not duplicating the code
  2. 您没有复制代码
  3. You are not using reflection (which is slow)
  4. 你没有使用反射(反射很慢)
  5. All of your conversions are in one place
  6. 所有的转换都在一个地方。

#16


0  

You can use an Extention:

你可以使用扩展:

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

In Code:

在代码:

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

}

#17


-1  

No, see this question which I asked - Upcasting in .NET using generics

不,看看我问的这个问题-在。net中使用泛型

The best way is to make a default constructor on the class, construct and then call an Initialise method

最好的方法是在类上创建一个默认构造函数,构造并调用初始化方法