Autor Beitrag
FrEEzE2046
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109

Windows 98, 2000, XP Pro, Vista Ultimate 32 & 64 Bit, Windows 7 Beta 64 Bit
C/C++, C# (VS 2008 TeamSystem) - Delphi (Delphi 5) - Java (Eclipse)
BeitragVerfasst: Di 18.05.10 21:29 
Hallo,

ich habe zwei Exception Klassen, welche ich als generic type für FaultException benutze. Beide Klassen haben ein string-Member Message und eine unterschiedliche enum mit dem Namen ErrorCode. Besteht die Möglichkeit eine entsprechende FaultException Variable zunächst abstrakt zu deklarieren und den genauen Typen erst durch Zuweisung zu bestimmen? Letztendlich sollen die Message und der ErrorCode (als string) in die Datei geschrieben werden und da die Behandlung für beide Typen gleicehn ist, würde ich mir gerne Redundanz ersparen. Ich habe mir das ungefähr so gedacht:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
[DataContract]
public enum Exception1ErrorCode
{
  None = 0,
  [EnumMember]
  First = 1,
  [EnumMember]
  Second = 2
  // [...]
}

[DataContract]
public class Exception1
{
  [DataMember]
  string Message;
  [DataMember]
  Exception1ErrorCode ErrorCode;
}


[DataContract]
public enum Exception2ErrorCode
{
  None = 0,
  [EnumMember]
  First = 1,
  [EnumMember]
  Second = 2
  // [...]
}

[DataContract]
public class Exception2
{
  [DataMember]
  string Message;
  [DataMember]
  Exception2ErrorCode ErrorCode;
}


public void Method()
{
  object faultException;
  
  iftrue )
  {
    faultException = new FaultException<Exception1>
    (
      new Exception1 { Message = "", ErrorCode = Exception1ErrorCode.First }
    );
  }
  else
  {
    faultException = new FaultException<Exception2>
    (
      new Exception2 { Message = "", ErrorCode = Exception2ErrorCode.First }
    );
  }
  
  using (StreamWriter sw = new StreamWriter(""))
  {
    sw.WriteLine(faultException.Detail.Message + '\t' + faultException.Detail.ErrorCode.ToString());
  }
}
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 18.05.10 23:15 
Die Generics spielen hier erst einmal gar keine Rolle ;) . Wenn du auf gleichnamige Member verschiedener Klassen zugreifen willst, brauchst du eine gemeinsame Basisklasse oder Interface - alles andere wäre Duck Typing (also in C# entweder Reflection oder doch eine if-Reihe). Aber warum nicht einfach bei beiden Typen ToString entsprechend überschreiben?

_________________
>λ=
FrEEzE2046 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109

Windows 98, 2000, XP Pro, Vista Ultimate 32 & 64 Bit, Windows 7 Beta 64 Bit
C/C++, C# (VS 2008 TeamSystem) - Delphi (Delphi 5) - Java (Eclipse)
BeitragVerfasst: Mi 19.05.10 11:15 
Eine gemeinsame Basisklasse macht aus zwei Gründen keinen Sinn:

1. Es sind DataMember, dieses Attribut würde nicht veerbt.
2. Nur Message ist ein gemeinsamer Typ (string).

ausblenden C#-Quelltext
1:
object o = Activator.CreateInstance(typeof(FaultException<>).MakeGenericType(typeof(ExceptionClass1)));					


So würde ich prinzipiell zumindest ein Objekt erstellen können, was aber dann wieder vom Typ object ist und ich müsste wieder mit "is" prüfen. Gibt es da wirklich keinen anderen Weg?


Da funktionieren die C++ Templates doch einfacher. Ich suche ungefähr so etwas in C#:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
#include <iostream>

using std::cout;
using std::string;


enum Exception1EnumCode { EXC1_None = 0, EXC1_First = 1, EXC1_Second = 2 };
enum Exception2EnumCode { EXC2_None = 0, EXC2_First = 1, EXC2_Second = 2 }; 


template<typename EnumType>
struct Exception
{
  string   Message;
  EnumType ErrorCode;
};

typedef struct Exception<Exception1EnumCode> Exception1;
typedef struct Exception<Exception2EnumCode> Exception2;


template<class T>
class GenericClass
{
public:
  T* data;
};


template<class T>
void print_generic_class(GenericClass<T>& gc)
{
  cout << gc.data->Message.c_str() << '\t' << gc.data->ErrorCode << '\n';
}


int main()
{  
  GenericClass<Exception1> gc1 = {new Exception1()};
  GenericClass<Exception2> gc2 = {new Exception2()};

  gc1.data->ErrorCode = EXC1_First;
  gc1.data->Message   = "Exception1";

  gc2.data->ErrorCode = EXC2_Second;
  gc2.data->Message   = "Exception2";
  
  print_generic_class(gc1);
  print_generic_class(gc2);

  delete gc1.data;
  delete gc2.data;

  return 0;
}
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 19.05.10 12:50 
Ich favorisiere immer noch ToString, aber ich gehe einfach mal davon aus, dass es dir auch ums Prinzip geht ;) .

user profile iconFrEEzE2046 hat folgendes geschrieben Zum zitierten Posting springen:
1. Es sind DataMember, dieses Attribut würde nicht veerbt.
Inherited = false spielt keine Rolle, solange du die Property nicht überschreibst :) .

user profile iconFrEEzE2046 hat folgendes geschrieben Zum zitierten Posting springen:
2. Nur Message ist ein gemeinsamer Typ (string).
Wenn du bestehenden Code nicht ändern kannst, kannst du immer noch welchen hinzufügen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
public abstract class ExceptionBase
{
  [DataMember]
  string Message;

  abstract string ErrorCodeAsString { get; }
}

[DataContract]
public class Exception1 : ExceptionBase
{
  [DataMember]
  Exception1ErrorCode ErrorCode;

  override string ErrorCodeAsString { get { return ErrorCode.ToString(); } }
}

...


user profile iconFrEEzE2046 hat folgendes geschrieben Zum zitierten Posting springen:
Da funktionieren die C++ Templates doch einfacher.
Templates werden zur Kompilierzeit ersetzt, Generics sind ein Runtime-Feature der CLR. Mit Ersterem bekommst du Duck Typing und kryptische Fehlermeldungen frei Haus, mit Letzterem keins von beidem.

_________________
>λ=
FrEEzE2046 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109

Windows 98, 2000, XP Pro, Vista Ultimate 32 & 64 Bit, Windows 7 Beta 64 Bit
C/C++, C# (VS 2008 TeamSystem) - Delphi (Delphi 5) - Java (Eclipse)
BeitragVerfasst: Mi 19.05.10 13:00 
So werde ich es dann wohl auch noch machen. Mir bringt es überhaupt nichts über Type zwar eine Instanz dieser Klasser zu erstellen, aber das Objekt dann nicht entsprechend verwenden zu können.

Ich kann also davon ausgehen, dass es keine solche Möglichkeit in C# gibt?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 19.05.10 13:42 
Du kannst davon ausgehen, dass keine einzige stark typisierte Sprache Duck Typing zur Laufzeit kennt. Und meiner Meinung nach braucht es das auch nicht zur Compile Time, da kann ich ja gleich Python einsetzen ;) .

_________________
>λ=
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 19.05.10 14:01 
Ich werf mal das Stichwort "dynamic" in die Runde. Gleichzeitig rate ich aber von der Verwendung ab und schließe mich Kha an das man das nicht braucht bzw. nicht verwenden sollte.
FrEEzE2046 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109

Windows 98, 2000, XP Pro, Vista Ultimate 32 & 64 Bit, Windows 7 Beta 64 Bit
C/C++, C# (VS 2008 TeamSystem) - Delphi (Delphi 5) - Java (Eclipse)
BeitragVerfasst: Mi 19.05.10 16:30 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Ich werf mal das Stichwort "dynamic" in die Runde. Gleichzeitig rate ich aber von der Verwendung ab und schließe mich Kha an das man das nicht braucht bzw. nicht verwenden sollte.


Ich werde eine abstrakte Klasse einführen, da das Member Message jede meiner Exception-Klassen hat. Dennoch habe ich mir auch "dynamic" angeschaut und es jetzt so gelöst:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
bUseFirst = true;
dynamic faultClass = null;

if (UseFirst)
  faultClass = new FirstClass();
else
    faultClass = new SecondClass();

Type exceptionType = typeof(FaultException<>);
Type faultType     = faultClass.GetType();
Type constructed   = exceptionType.MakeGenericType(faultType);

try
{
  throw Activator.CreateInstance(constructed, new object[] {faultClass}) as FaultException;
}
catch (FaultException<FirstClass> e)
{
    Console.WriteLine("Catched FirstClass");
}
catch (FaultException<SecondClass> e)
{
    Console.WriteLine("Catched SecondClass");
}
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 19.05.10 17:13 
user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Ich werf mal das Stichwort "dynamic" in die Runde.
Ich habe lieber auf Reflection verwiesen, damit grausiges Design auch entsprechend mit grausigem Code markiert ist :mrgreen: .

user profile iconFrEEzE2046 hat folgendes geschrieben Zum zitierten Posting springen:
Dennoch habe ich mir auch "dynamic" angeschaut und es jetzt so gelöst:
In deinem Code benutzt du überhaupt kein Feature von dynamic, da könnte genauso gut object stehen.

_________________
>λ=
FrEEzE2046 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109

Windows 98, 2000, XP Pro, Vista Ultimate 32 & 64 Bit, Windows 7 Beta 64 Bit
C/C++, C# (VS 2008 TeamSystem) - Delphi (Delphi 5) - Java (Eclipse)
BeitragVerfasst: Do 20.05.10 11:36 
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
In deinem Code benutzt du überhaupt kein Feature von dynamic, da könnte genauso gut object stehen.


Ja, da hast du natürlich recht. Ich habe aber doch gesagt, dass ich immer auf Message u. ErrorCode zugreifen muss und das ist dann schon ein Feature von dynamic, was ich nutze.

Den Code oben, hab ich schnell in einem Konsolenprogramm erstellt.