2009-02-19 14 views
6

ich zur Zeit diese Art von Code haben:C#: Casting-Typen dynamisch

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    if (MainObject is SomeClassType1) 
    { 
     SomeClassType1 HelpObject = (SomeClassType1)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     SomeClassType2 HelpObject = (SomeClassType2)MainObject; 
     HelpObject.Property1 = Arg1; 
     HelpObject.Property2 = Arg2; 
    } 
} 

Unter der Annahme, dass SomeClassType1 und SomeClassType2 den gleichen Satz von Eigenschaften, die ich zugewiesen werden soll (obwohl sie in anderen abweichen können), ist es möglich, MainObject dynamisch auf den entsprechenden Typ zu werfen und dann den Wert zuzuweisen, ohne den Code zu duplizieren? Diese ist, was ich am Ende sehen möchten:

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type DynamicType = null; 

    if (MainObject is SomeClassType1) 
    { 
     DynamicType = typeof(SomeClassType1); 
    } 
    else if (MainObject is SomeClassType2) 
    { 
     DynamicType = typeof(SomeClassType2); 
    } 

    DynamicType HelpObject = (DynamicType)MainObject; 
    HelpObject.Property1 = Arg1; 
    HelpObject.Property2 = Arg2; 
} 

Und natürlich beschwert C# über nicht in der Lage DynamicType zu finden:

Der Typ oder Namespace-Name ‚DynamicType‘ konnte nicht gefunden werden (fehlt eine Verwendungsrichtlinie oder eine Baugruppenreferenz?)

Ist in C# 2.0 so etwas möglich? Wenn es unordentlicher ist als mein aktueller Code, sehe ich keinen Sinn darin, das zu tun, aber ich bin sehr daran interessiert, es herauszufinden. Vielen Dank!

EDIT: Nur um zu verdeutlichen, verstehe ich perfekt, dass die Implementierung einer Schnittstelle die am besten geeignete und wahrscheinlich richtige Lösung ist. Das heißt, ich bin mehr daran interessiert zu sehen, wie ich es ohne eine Schnittstelle implementieren könnte. Danke für tolle Antworten!

Antwort

15

Es sieht aus wie beide Typen die gleichen zwei Eigenschaften implementieren Sie sich interessieren. In diesem Fall, was Sie wollen ist eine Schnittstelle für diese Eigenschaften tun definieren:

public interface IMyInterface 
{ 
    public Foo Property1 {get; set;} 
    public Bar Property2 {get;set;} 
} 

Dann stellen Sie sicher, dass jede Ihrer Klassen den Compiler sagen, dass sie die neue Schnittstelle implementieren. Schließlich eine generische Methode mit einem Typ-Argument verwenden, die zu diesem interace eingeschränkt ist:

private void FillObject<T>(T MainObject, Foo Arg1, Bar Arg2) 
    where T : IMyInterface 
{ 
    MainObject.Property1 = Arg1; 
    MainObject.Property2 = Arg2; 
} 

Beachten Sie, dass auch mit dem zusätzlichen Code, um die Schnittstelle zu erklären, enden diese Schnipsel immer noch kürzer als eine der Schnipsel Sie auf dem Laufenden in der Frage, und dieser Code ist viel einfacher zu erweitern, wenn die Anzahl der Typen, die Sie interessieren, zunimmt.

+1

+1 Schön ... Ich hätte nicht gedacht, Generika zu verwenden, ich hätte einfach auf die Schnittstelle geworfen. –

+0

Wie ist der generische Parameter T hier sinnvoll? Warum nicht einfach FillObject (IMyInterface mainobject, ...) verwenden? –

+0

Ich bin neugierig - warum würden Sie Generika in diesem Fall und nicht nur private void FillObject (IMyInterface MainObject, Foo Arg1, Bar Arg2) verwenden? –

9

Im Wesentlichen schreiben Sie hier eine switch-Anweisung basierend auf dem Typ des Objekts. Es gibt keinen grundsätzlich guten Weg, dies zu tun, außer Ihrem ersten Beispiel (das im besten Fall mühsam ist).

Ich schrieb ein kleines Framework für das Einschalten von Typen, die die Syntax ein wenig prägnanter macht. Es ermöglicht Ihnen, Code wie folgt zu schreiben.

TypeSwitch.Do(
    sender, 
    TypeSwitch.Case<Button>(
     () => textBox1.Text = "Hit a Button"), 
    TypeSwitch.Case<CheckBox>(
     x => textBox1.Text = "Checkbox is " + x.Checked), 
    TypeSwitch.Default(
     () => textBox1.Text = "Not sure what is hovered over")); 

Blog: http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx

2

Statt zu werfen versuchen, vielleicht könnten Sie versuchen, die Eigenschaften Einstellung mit Reflexion.

4
private void FillObject(Object MainObject, Foo Arg1, Bar Arg2) 
{ 
    Type t = MainObject.GetType(); 

    t.GetProperty("Property1").SetValue(MainObject, Arg1, null); 
    t.GetProperty("Property2").SetValue(MainObject, Arg2, null); 
} 
+0

Ich denke Generika sind hier besser geeignet, aber zumindest würde ich überprüfen, um sicherzustellen, dass die Eigenschaften zuerst existieren. –

+0

Ich wollte nur demonstrieren, wie man es mit Reflektion macht. Dies ist kein * vollständiger * oder * empfohlener Ansatz für dieses Problem. –

+0

Ich denke, das hat eine Katastrophe überall geschrieben ... –

7

Können Sie Änderungen an SomeClassType1, SomeClassType2 usw. vornehmen? Wenn ja, schlage ich vor, dass Sie eine Schnittstelle erstellen, die Ihre allgemeinen Eigenschaften enthält, und dann an diese Schnittstelle innerhalb von FillObject() tippen, um die Eigenschaften festzulegen.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace SO566510 
{ 
    interface IMyProperties 
    { 
     int Property1 { get; set; } 
     int Property2 { get; set; } 
    } 

    class SomeClassType1 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 

    class SomeClassType2 : IMyProperties 
    { 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var obj1 = new SomeClassType1(); 
      var obj2 = new SomeClassType2(); 

      FillObject(obj1, 10, 20); 
      FillObject(obj2, 30, 40); 

     } 

     private static void FillObject(IMyProperties objWithMyProperties 
            , int arg1, int arg2) 
     { 
      objWithMyProperties.Property1 = arg1; 
      objWithMyProperties.Property2 = arg2; 
     } 
    } 
} 
+0

Obwohl das sicherlich eine Option ist, wird es für die einfache Sache, die ich erreichen möchte, ein Overkill sein. Mein Code ist im Grunde, was ich oben gepostet habe, mit nur ein paar Typen und Variablennamen geändert. –

+0

Ich wollte das gleich vorschlagen. Wenn sie dieselben öffentlich verfügbaren Eigenschaften haben, scheint eine Schnittstelle angemessen zu sein. –

+0

@MK_Dev: Es ist nicht so viel Arbeit, die Sie denken, es ist, müssen Sie es versuchen. In der Tat könnte es am Ende die Größe Ihres Codes reduzieren. –

3

Einige Ideen:

  1. Haben beide Typen erben von der gleichen Art, die die gemeinsamen Eigenschaften
  2. haben, haben beide Arten die gleiche Schnittstelle implementieren, die die gemeinsamen Eigenschaften
  3. Verwenden Reflexion die Eigenschaften setzen müssen anstatt sie direkt zu setzen (das ist wahrscheinlich hässlicher als es wert ist)
  4. Verwenden Sie die neue dynamic feature, ich habe dies nicht versucht, aber sieht aus wie es Ihr Problem beheben könnte
0

Ich bin Objekte dynamisch mit Reflection in einer ASP.NET MVC App. Grundsätzlich liste ich die Eigenschaften einer Klasse auf, finde den entsprechenden Wert im Datenspeicher und werfe den Wert dynamisch um und ordne ihn der Objektinstanz zu. Sehen Sie meinen Blog-Beitrag Dynamic Casting with .NET