명시 적 형변환을 사용하여 파생 클래스 참조에 기본 클래스 개체를 할당 할 수 있습니까?


88

C #에서 명시 적 형식 변환을 사용하여 파생 클래스 참조에 기본 클래스 개체를 할당 할 수 있습니까?

나는 그것을 시도했고 런타임 오류가 발생합니다.

답변:


98

아니요. 파생 클래스에 대한 참조는 실제로 파생 클래스의 인스턴스 (또는 null)를 참조해야합니다. 그렇지 않으면 어떻게 작동 할 것으로 예상합니까?

예를 들면 :

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

기본 형식의 인스턴스를 파생 형식으로 변환하려면 적절한 파생 형식 인스턴스를 만드는 메서드를 작성하는 것이 좋습니다. 또는 상속 트리를 다시보고 처음부터이 작업을 수행 할 필요가 없도록 재 설계를 시도하십시오.


72
@Mike : 코드가 잘 컴파일됩니다. 하지만 실행 시간에 넘어갑니다. :)
Jon Skeet

1
그렇다면 Base b = new Derived (); ? 기본 및 파생 클래스 모두에 대한 개체를 생성합니까?
Ashif 나탈리아

3
@Akie : 아니요, 유형의 단일 객체를 생성 Derived하지만 Derived참조를 참조로 취급 할 수 있습니다 Base.
Jon Skeet

그렇다면이 두 문장의 결과 객체에 차이가 있습니까? Base b = new Base () 및 Base b = new Derived ()? 하나를 다른 것보다 사용하면 어떤 이점이 있습니까?
Ashif 나탈리아

4
@Akie : 예, 하나는의 인스턴스를 Base만들고 다른 하나는의 인스턴스를 만듭니다 Derived. b에서 재정의 된 가상 메서드를 호출 하면 인스턴스가있는 경우 동작 Derived이 표시 됩니다. 그러나 Stack Overflow 주석 스레드의 세부 사항으로 들어가는 것은 실제로 적절하지 않습니다. 이것은 매우 기본적인 내용이므로 좋은 C # 책이나 자습서를 읽어야합니다. DerivedDerived
Jon Skeet

46

아니요, 파생 클래스 참조에 할당하는 것은 "기본 클래스는 파생 클래스를 완전히 대체 할 수 있습니다. 파생 클래스가 할 수있는 모든 작업을 수행 할 수 있습니다."라고 말하는 것과 같기 때문에 불가능합니다. 이는 일반적으로 파생 클래스가 제공하므로 사실이 아닙니다. 기본 클래스보다 더 많은 기능을 제공합니다 (적어도 상속의 개념입니다).

기본 클래스 개체를 매개 변수로 사용하여 값을 복사하는 파생 클래스에 생성자를 작성할 수 있습니다.

이 같은:

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

이 경우 기본 개체를 복사하고 파생 멤버에 대한 기본값이있는 완전한 기능의 파생 클래스 개체를 가져옵니다. 이렇게하면 Jon Skeet이 지적한 문제를 피할 수도 있습니다.

Base b = new Base();//base class
Derived d = new Derived();//derived class

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!

23

이 문제가 발생하여 유형 매개 변수를 사용하고 현재 개체를 해당 유형으로 변환하는 메서드를 추가하여 해결했습니다.

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

현재 클래스 (기본 클래스)의 유형을 사용하여 속성을 가져오고 설정해야합니다. 속성은 파생 클래스에 매핑하려는 값이기 때문입니다.
Bowofola

1
파생 된 형식에 쓸 수없는 속성이있는 경우 다음과 같이 변경해야합니다. if (property.CanWrite) property.SetValue (instance, property.GetValue (this, null), null);
user3478586

10

다른 많은 사람들이 대답했듯이 아니요.

기본 형식을 파생 형식으로 사용해야하는 경우에 다음 코드를 사용합니다. 예, 그것은 Liskov Substitution Principle (LSP)에 위배되며, 그렇습니다. 우리는 대부분 상속보다 구성을 선호합니다. Markus Knappen Johansson의 원래 답변을 기반으로 한 소품입니다.

기본 클래스의이 코드 :

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

반사를 사용하기 때문에 "비싸다". 그에 따라 사용하십시오.


나는 방금 이것을 시도했고, 명시 적 연산자 (그리고 암시 적 연산자도)를 오버로딩함으로써 더 개선 될 수 있다고 생각했다. 그러나-컴파일러는 그것을 허용하지 않을 것이다 : user-defined conversions to or from a base class are not allowed 나는 이것에 대한 이유를 보았지만 실망했다. 그것은 너무 재미했을로이 ... 허용 한 경우
헨릭

@MEC :`where T : MyBaseClass` 부분을 삭제하고 if (type.BaseType != null)Markus Knappen Johansson의 A 와 관련된 Statement를 추가했습니다 . 그 이유는 무엇입니까? 즉, MyBaseClass에서 파생되지 않은 유형 (또는 그 문제에 대한 모든 것)을 호출에 허용합니다. myDerivedObject에 할당하면 여전히 컴파일러 오류가 발생한다는 것을 알고 있지만 표현식으로 만 사용하면 컴파일되고 런타임에 "myBaseObject"에서 복사 된 데이터없이 myDerivedObject 만 생성됩니다. 나는 그것을위한 유스 케이스를 상상할 수 없다.
Tom

@Tom, 늦게 회신했지만 여전히 유용 할 것이라고 생각했습니다. 귀하의 질문에 대한 가장 좋은 답변은 "As"라는 이름이 "AsOrDefault"가 더 낫다고 말하는 것입니다. 본질적으로 우리는이 결과를 가져 와서 Linq의 SingleOrDefault 또는 FirstOrDefault를 사용할 때처럼 Default와 비교할 수 있습니다.
MEC

7

불가능하므로 런타임 오류가 발생합니다.

그러나 파생 클래스의 인스턴스를 기본 클래스 유형의 변수에 할당 할 수 있습니다.


7

JsonConvert를 사용한 솔루션 (타입 캐스트 대신)

오늘은 동일한 문제에 직면하고 난 간단하고 발견 문제에 대한 빠른 솔루션을 사용 JsonConvert.

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

아래에서 확장 방법으로 다시 대답했습니다. 네, 이것이 답입니다.
Patrick Knott

5

여기 모두가 말했듯이, 그것은 직접적으로 가능하지 않습니다.

내가 선호하고 다소 깨끗한 방법은 AutoMapper 와 같은 Object Mapper를 사용하는 것 입니다 .

한 인스턴스에서 다른 인스턴스 (동일한 유형일 필요는 없음)로 속성을 자동으로 복사하는 작업을 수행합니다.


3

@ybo의 대답을 확장하면 기본 클래스의 인스턴스가 실제로 파생 클래스의 인스턴스가 아니기 때문에 가능하지 않습니다. 기본 클래스의 멤버에 대해서만 알고 있으며 파생 클래스의 멤버에 대해서는 알지 못합니다.

파생 클래스의 인스턴스를 기본 클래스의 인스턴스로 캐스팅 할 수있는 이유는 파생 클래스에 이미 해당 멤버가 있기 때문에 실제로 이미 기본 클래스의 인스턴스이기 때문입니다. 그 반대는 말할 수 없습니다.


3

기본 클래스로 형식화 된 변수 를 파생 클래스 형식으로 캐스팅 할 수 있습니다 . 그러나 필요에 따라 관련된 실제 개체가 올바른 유형인지 확인하기 위해 런타임 검사를 수행합니다.

생성 된 객체 의 유형 은 변경할 수 없습니다 (최소한 크기가 같지 않을 수 있음). 그러나 인스턴스를 변환 하여 두 번째 유형 의 인스턴스를 만들 수 있지만 변환 코드를 수동으로 작성해야합니다.


2

아니요, 불가능합니다.

ACBus가 기본 클래스 Bus의 파생 클래스 인 시나리오를 고려하십시오. ACBus에는 ACState라는 필드에서 작동하는 TurnOnAC 및 TurnOffAC와 같은 기능이 있습니다. TurnOnAC는 ACState를 켜기로 설정하고 TurnOffAC는 ACState를 끄기로 설정합니다. 버스에서 TurnOnAC 및 TurnOffAC 기능을 사용하려고하면 의미가 없습니다.


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

}

자식 클래스 개체를 만들 때 기본 클래스 개체가 자동으로 시작되므로 기본 클래스 참조 변수가 자식 클래스 개체를 가리킬 수 있습니다.

그러나 하위 클래스 개체가 생성되지 않았기 때문에 하위 클래스 참조 변수가 기본 클래스 개체를 가리킬 수 없기 때문에 그 반대는 아닙니다.

또한 기본 클래스 참조 변수는 기본 클래스 멤버 만 호출 할 수 있습니다.


2

실제로이를 수행하는 방법이 있습니다. Newtonsoft JSON을 사용하여 json에서 객체를 역 직렬화하는 방법을 생각해보십시오. 누락 된 요소를 무시하고 알고있는 모든 요소를 ​​채 웁니다.

그래서 내가 한 방법입니다. 작은 코드 샘플이 내 설명을 따릅니다.

  1. 기본 클래스에서 개체의 인스턴스를 만들고 그에 따라 채 웁니다.

  2. Newtonsoft json의 "jsonconvert"클래스를 사용하여 해당 객체를 json 문자열로 직렬화합니다.

  3. 이제 2 단계에서 만든 json 문자열로 역 직렬화하여 하위 클래스 개체를 만듭니다. 그러면 기본 클래스의 모든 속성을 사용하여 하위 클래스의 인스턴스가 생성됩니다.

이것은 매력처럼 작동합니다! 그래서 ..이게 언제 유용할까요? 어떤 사람들은 이것이 언제 이치에 맞는지 물었고 (.Net에서) 클래스 상속으로 기본적으로 이것을 할 수 없다는 사실을 수용하기 위해 OP의 스키마를 변경하도록 제안했습니다.

제 경우에는 서비스에 대한 모든 "기본"설정을 포함하는 설정 클래스가 있습니다. 특정 서비스에는 더 많은 옵션이 있으며 다른 DB 테이블에서 제공되므로 해당 클래스는 기본 클래스를 상속합니다. 그들은 모두 다른 옵션 세트를 가지고 있습니다. 따라서 서비스에 대한 데이터를 검색 할 때 기본 개체의 인스턴스를 사용하여 값을 먼저 채우는 것이 훨씬 쉽습니다. 단일 DB 쿼리로이를 수행하는 한 가지 방법입니다. 그 직후 위에서 설명한 방법을 사용하여 하위 클래스 개체를 만듭니다. 그런 다음 두 번째 쿼리를 만들고 하위 클래스 개체의 모든 동적 값을 채 웁니다.

최종 출력은 모든 옵션이 설정된 파생 클래스입니다. 추가 새 하위 클래스에 대해이 작업을 반복하면 몇 줄의 코드 만 필요합니다. 간단하고, 매우 검증 된 패키지 (Newtonsoft)를 사용하여 마법을 작동시킵니다.

이 예제 코드는 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)

C # 및 Newtonsoft.Json 사용 : var destObject = JsonConvert.DeserializeObject<DestinationType>(JsonConvert.SerializeObject(srcObject));. 나는 단위 테스트 및 기타 비 프로덕션 "해킹"에만 이것을 사용합니다!
thinkOfaNumber

2

확장을 사용할 수 있습니다.

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

}

1

관련성이 없을 수도 있지만 기반이 주어진 파생 개체에서 코드를 실행할 수있었습니다. 내가 원하는 것보다 확실히 더 해키하지만 작동합니다.

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

1

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

이 접근 방식을 사용하면 세 가지 이점을 얻을 수 있습니다.

  1. 코드를 복제하지 않습니다.
  2. 반사를 사용하지 않습니다 (느림)
  3. 모든 전환이 한곳에 있습니다.

1

나는 이것이 오래되었다는 것을 알고 있지만 꽤 오랫동안 성공적으로 사용했습니다.

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

1

이전 답변의 일부를 결합하고 (저자 덕분에) 우리가 사용하는 두 가지 방법으로 간단한 정적 클래스를 구성했습니다.

예, 간단합니다. 아니요 모든 시나리오를 다룰 수는 없습니다. 예 확장되고 더 나아질 수 있습니다. 아니요 완벽하지 않습니다. 예, 더 효율적으로 만들 수 있습니다. 아니요 슬라이스 빵 이후로 가장 좋은 것은 아닙니다. 예 강력한 너겟 패키지 객체 매퍼는 과도하게 사용하는 등의 방법이 더 좋습니다. yada yada-그러나 기본 요구 사항에는 작동합니다. :)

그리고 물론 어떤 객체의 값을 파생되거나 파생되지 않은 객체로 매핑하려고 시도합니다 (물론 이름이 같은 공용 속성 만 나머지는 무시합니다).

용법:

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

1

인스턴스 생성자를 즉시 ​​호출하는 복사 생성자를 사용하거나 인스턴스 생성자가 할당보다 더 많은 작업을 수행하는 경우 복사 생성자가 들어오는 값을 인스턴스에 할당하도록 할 수 있습니다.

class Person
{
    // Copy constructor 
    public Person(Person previousPerson)
    {
        Name = previousPerson.Name;
        Age = previousPerson.Age;
    }

    // Copy constructor calls the instance constructor.
    public Person(Person previousPerson)
        : this(previousPerson.Name, previousPerson.Age)
    {
    }

    // Instance constructor.
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public int Age { get; set; }

    public string Name { get; set; }
}

이전에이 문제가 있었던이 예제에 대해 생성자 아래Microsoft C # 설명서를 참조했습니다 .


0

또 다른 해결책은 다음과 같은 확장 방법을 추가하는 것입니다.

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

또한 이미 설정되어 있거나 (null이 아님) 대상 속성을 선택적으로 덮어 씁니다.


0

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물결 선이 없습니다.


이게 무슨 흑 마법?!? 또한 "Derived z = new Base ()"가 "BaseCls baseObj; DerivedCls derivedObj; derivedObj = (DerivedCls) baseObj"(OP의 Q)를 수행하는 데 어떻게 도움이됩니까? 또한 System.Runtime.CompilerServices.SpecialNameAttribute는 무엇을합니까? 사용 가능한 초기 버전 (2.0)에서 "현재 버전"(4.6? "anyone? anyone?")에 이르는 모든 버전에 대한 문서는 그것이 무엇을하는지 말하지 않고 "SpecialNameAttribute 클래스는 현재 .NET에서 사용되지 않습니다. 프레임 워크이지만 향후 사용을 위해 예약되어 있습니다. ". 참조 : [link] ( msdn.microsoft.com/en-us/library/ms146064(v=vs.100).aspx ).

> "이건 무슨 흑 마법이야?!?" 이를 .Net Framework (CLR, IL, BCL)라고합니다. IL, C # 및 VB 언어의 기능 세트는 동일하지 않습니다. VB에는 C #이 지원하지 않는 기능이 있습니다. IL에는 C #이 지원하지 않는 기능이 있습니다. C #에는 다소 임의적이며 기본 IL에는 존재하지 않는 제한이 있습니다 (예 where T : Delegate: 인덱서 등의 매개 변수화 된 속성).
Ark-kun

> "또한"Derived z = new Base () "가"BaseCls baseObj; DerivedCls 파생 Obj; derivedObj = (DerivedCls) baseObj "(OP의 Q)?" 그냥 그렇습니다. OP의 질문을 해결합니다. 그리고 명시적인 캐스트도 필요하지 않습니다.
Ark-kun

> what does System.Runtime.CompilerServices.SpecialName Attribute do?-속성 접근 자, 이벤트 접근 자, 생성자, 연산자, 인덱서 등 고급 .Net 언어의 특수한 편의 구조에 의해 생성 된 메서드를 표시하는 데 사용됩니다. IL 메서드가 표시되지 않는 한 표시 specialname되지 않습니다. 속성 / 이벤트 / 생성자로서 일반적인 방법으로 인식됩니다. 이 속성을 사용하여 적절하게 이름이 지정된 메서드를 수동으로 표시하는 것은 컴파일러 작업의 일부를 수동으로 수행하는 것입니다.
Ark-kun

VB.Net에는 전력 연산자가 있습니다. C #은 그렇지 않습니다. VB.Net에서 사용하기 위해 C #에서 전력 연산자를 어떻게 오버로드합니까? op_Exponent메소드를 정의 하고 specialname속성으로 표시하기 만하면 됩니다.
Ark-kun

0

어때 :

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

0

파생 항목에 모든 기본 속성을 추가하는 가장 좋은 방법은 코스 트럭 터에서 리플렉션을 사용하는 것입니다. 메서드 나 인스턴스를 만들지 않고이 코드를 사용해보십시오.

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

    }

0

나는 그것이 불가능하다는 데 동의하지 않습니다. 다음과 같이 할 수 있습니다.

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

var auto =여전히 유형입니다sedan
bendecko

0

이것이 내가 분야에서 이것을 해결 한 방법입니다. 원하는 경우 속성을 통해 동일한 반복을 수행 할 수 있습니다. null등을 확인하고 싶을 수도 있지만 이것이 아이디어입니다.

 public static DerivedClass ConvertFromBaseToDerived<BaseClass, DerivedClass>(BaseClass baseClass)
            where BaseClass : class, new()
            where DerivedClass : class, BaseClass, new()
        {
            DerivedClass derived = (DerivedClass)Activator.CreateInstance(typeof(DerivedClass));
            derived.GetType().GetFields().ToList().ForEach(field =>
            {
                var base_ = baseClass.GetType().GetField(field.Name).GetValue(baseClass);
                field.SetValue(derived, base_);

            });

            return derived;
        }

0

기본 개체를 JSON으로 직렬화 한 다음 파생 된 개체로 역 직렬화 할 수 있습니다.


0

전통적인 감각이 아닙니다 ... Json으로 변환 한 다음 개체로 변환하고 붐, 완료! 위의 Jesse는 먼저 답변을 게시했지만 프로세스를 훨씬 쉽게 만드는 이러한 확장 방법을 사용하지 않았습니다. 몇 가지 확장 메서드를 만듭니다.

    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 derivedClass = baseClass.ConvertToJson().ConvertToObject<derivedClass>();

아, JSON의 힘.

이 접근 방식에는 몇 가지 문제가 있습니다. 우리는 실제로 캐스팅이 아닌 새 개체를 만들고 있는데, 이는 중요하거나 중요하지 않을 수 있습니다. 개인 필드가 전송되지 않고 매개 변수가있는 생성자가 호출되지 않습니다. 일부 자식 json이 할당되지 않을 수 있습니다. 스트림은 JsonConvert에 의해 본질적으로 처리되지 않습니다. 그러나 우리 클래스가 private 필드와 생성자에 의존하지 않는다면, 이것은 생성자를 매핑하고 호출하지 않고 클래스에서 클래스로 데이터를 이동하는 매우 효과적인 방법이며, 이것이 우리가 처음에 캐스팅하려는 주된 이유입니다.


이것은 OP가 요청한 것을 수행하지 않습니다. 당신이하는 일은 잘못된 유형의 원래 객체의 데이터를 사용하여 변수에 대해 올바른 유형의 새 객체를 생성하는 것입니다. 이것은 작동 할 수도 있고 작동하지 않을 수도 있지만 어느 쪽이든 기본 클래스 유형의 개체를 파생 유형의 변수에 할당하지 않습니다.
Lasse V. Karlsen

질문에 대답했습니다. 명시 적 형식 변환을 사용하여 파생 클래스 참조에 기본 클래스 개체를 할당 할 수 있습니까? 아니오라고 말함으로써. 나는 절대적으로 작동하고 제네릭보다 덜 혼란스러운 대안을 제공하고 있습니다. 위에서 여러 번 언급했듯이 기본 클래스에서 파생 된 클래스 속성에 할당하는 데 문제가 발생할 수 있지만 이것이 가능하다면 정확히 작동하는 방식 (API에서 수행)입니다. 내 대답이 "잘못된"유형에서 사용될 수 있다고해서 "올바른"유형에 사용할 수 없다는 의미는 아닙니다. @ LasseV.Karlsen은 부정적인 평가를 철회하십시오.
Patrick Knott

데이지 체인 JsonConverts에 대한 대부분의 답변과 달리 null을 처리하는 방법도 보여줍니다.
Patrick Knott

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.