Ik zit met het volgende probleem: In mijn applicatie maak ik gebruik van plugins. Een plugin is gewoon een klasse die erft van een klasse Plugin. Bij het opstarten loop ik alle plugins in de plugin-folder af om te kijken welke plugins er aanwezig zijn. Deze worden door middel van reflection bekeken om te kijken welke public variabelen ze hebben. Deze informatie gebruik ik voor het automatisch genereren van een Form waarmee je de variabelen kan beinvloeden en voor (de nog te implementeren) scripting engine.
Aangezien ik bepaalde metadata nodig heb (minimum waarde, maximum waarde bijvoorbeeld) gebruik ik hiervoor geen standaard .Net datatypen, maar zelf gebakken klasses. Hieronder een deel van de huidige implementatie:
om vervolgens deze klassen te gebruiken in de plugin gebruik je de volgende code:
Op zich werkt dit, maar er zitten wel wat scherpe kantjes aan. Ten eerste heb ik ook nog ARFloat4 en ARFloat5 klassen, daarnaast heb ik ook nog integers. Oftewel ik heb nog 5 klassen waarin ik dmv zoeken en vervangen alle floats door ints vervang. Dat is niet volgens de regel Do Not Repeat Yourself. Ook moet ik dus om nieuwe functionaliteit toe te voegen 10 klassen aanpassen.
Het eerste idee was om generics te gebruiken (dan zou ik iig de helft van het aantal klasses overhouden), maar dat kan omdat het niet mogelijk is om met Generics te rekenen. Het toevoegen van een IArithmetic interface aan het .net framework zou dit oplossen (zie bijvoorbeeld dit artikel) en het schijnt dat in op dit moment hiernaar gekeken wordt voor de 4.0 release. Maar daar ga ik natuurlijk niet op wachten.
Heeft iemand suggesties over hoe ik dit beter zou kunnen implementeren?
Aangezien ik bepaalde metadata nodig heb (minimum waarde, maximum waarde bijvoorbeeld) gebruik ik hiervoor geen standaard .Net datatypen, maar zelf gebakken klasses. Hieronder een deel van de huidige implementatie:
code:
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
| public class ARFloat : ARBaseVar, IVarFloat {
private float min = -500;
private float max = 500;
private float inc = 1;
private float val = 0;
public bool Loop = false;
public ARFloat() { }
public ARFloat(float v) { Value = v; }
public void SetAttributes(string n, float mi, float ma, float i) {
name = n;
min = mi;
max = ma;
inc = i;
}
public float Value {
get { return val; }
set {
if (value >= min && value <= max)
val = value;
else if (Loop) {
if (value < min) {
val = max;
} else {
val = min;
}
}
}
}
public override System.Windows.Forms.UserControl GetControl() {
return ARVarGuiFactory.GetUserControl(this);
}
public float Min { get { return min; } }
public float Max { get { return max; } }
public float Inc { get { return inc; } }
public override string ToXml(bool enclose) {
return "<ARFloat loop=\"" + Loop + "\">" + val.ToString() + "</ARFloat>\r\n";
}
public override void FromXml(XmlReader reader) {
PresetLoader.LoadARVar(this, reader);
}
}
public class ARFloat2 : ARBaseVar, IVarFloat {
protected ARFloat x;
protected ARFloat y;
public ARFloat2() {
x = new ARFloat();
y = new ARFloat();
}
public ARFloat2(float xx, float yy) {
x = new ARFloat(xx);
y = new ARFloat(yy);
}
public void Set(float xx, float yy) {
this.x.Value = xx;
this.y.Value = yy;
}
public virtual void SetAttributes(string n, float mi, float ma, float i) {
this.name = n;
x.SetAttributes(name, mi, ma, i);
y.SetAttributes(name, mi, ma, i);
}
public ARFloat X { get { return x; } set { x = value; } }
public ARFloat Y { get { return y; } set { y = value; } }
public override System.Windows.Forms.UserControl GetControl() {
return ARVarGuiFactory.GetUserControl(this);
}
public float Min { get { return x.Min; } }
public float Max { get { return x.Max; } }
public float Inc { get { return x.Inc; } }
public override string ToXml(bool enclose) {
string ret = x.ToXml(false) + y.ToXml(false);
if (enclose)
return "<ARFloat2>\r\n" + ret + "</ARFloat2>\r\n";
else
return ret;
}
public virtual bool Loop {
set {
x.Loop = value;
y.Loop = value;
}
}
public override void FromXml(XmlReader reader) {
PresetLoader.LoadARVar(this, reader);
}
}
public class ARFloat3 : ARFloat2, IVarFloat {
protected ARFloat z;
public ARFloat3()
: base() {
z = new ARFloat();
}
public ARFloat3(float xx, float yy, float zz)
: base(xx, yy) {
z = new ARFloat(zz);
}
public void Set(float xx, float yy, float zz) {
base.Set(xx, yy);
this.z.Value = zz;
}
public override void SetAttributes(string n, float mi, float ma, float i) {
base.SetAttributes(n, mi, ma, i);
z.SetAttributes(n, mi, ma, i);
}
public ARFloat Z { get { return z; } set { z = value; } }
public Vector3 ToVector3() {
return new Vector3(this.x.Value, this.y.Value, this.Z.Value);
}
public override System.Windows.Forms.UserControl GetControl() {
return ARVarGuiFactory.GetUserControl(this);
}
public override string ToXml(bool enclose) {
string ret = base.ToXml(false) + z.ToXml(false);
if (enclose)
return "<ARFloat3>\r\n" + ret + "</ARFloat3>\r\n";
else
return ret;
}
public override void FromXml(XmlReader reader) {
PresetLoader.LoadARVar(this, reader);
}
public override bool Loop {
set {
base.Loop = value;
z.Loop = value;
}
}
} |
om vervolgens deze klassen te gebruiken in de plugin gebruik je de volgende code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class PluginDing : Plugin {
//[ARFloatAttribute("Naam in Form", min, max, increment)]
[ARFloatAttribute("Size", -1000f, 1000f, 0.2f)]
public ARFloat2 size;
[ARIntAttribute("Texture", 0, 63, 1)]
public ARInt Texture;
public PluginDing() {
//initialiseer shit...
}
public void DoeIets() {
//doe nuttige shit
}
} |
Op zich werkt dit, maar er zitten wel wat scherpe kantjes aan. Ten eerste heb ik ook nog ARFloat4 en ARFloat5 klassen, daarnaast heb ik ook nog integers. Oftewel ik heb nog 5 klassen waarin ik dmv zoeken en vervangen alle floats door ints vervang. Dat is niet volgens de regel Do Not Repeat Yourself. Ook moet ik dus om nieuwe functionaliteit toe te voegen 10 klassen aanpassen.
Het eerste idee was om generics te gebruiken (dan zou ik iig de helft van het aantal klasses overhouden), maar dat kan omdat het niet mogelijk is om met Generics te rekenen. Het toevoegen van een IArithmetic interface aan het .net framework zou dit oplossen (zie bijvoorbeeld dit artikel) en het schijnt dat in op dit moment hiernaar gekeken wordt voor de 4.0 release. Maar daar ga ik natuurlijk niet op wachten.
Heeft iemand suggesties over hoe ik dit beter zou kunnen implementeren?