Joa*_*oao 4 c# reflection types runtime
说我有以下代码:
// a class like this
class FirstObject {
public Object OneProperty {
get;
set;
}
// (other properties)
public Object OneMethod() {
// logic
}
}
// and another class with properties and methods names
// which are similar or exact the same if needed
class SecondObject {
public Object OneProperty {
get;
set;
}
// (other properties)
public Object OneMethod(String canHaveParameters) {
// logic
}
}
// the consuming code would be something like this
public static void main(String[] args) {
FirstObject myObject=new FirstObject();
// Use its properties and methods
Console.WriteLine("FirstObject.OneProperty value: "+myObject.OneProperty);
Console.WriteLine("FirstObject.OneMethod returned value: "+myObject.OneMethod());
// Now, for some reason, continue to use the
// same object but with another type
// -----> CHANGE FirstObject to SecondObject HERE <-----
// Continue to use properties and methods but
// this time calls were being made to SecondObject properties and Methods
Console.WriteLine("SecondObject.OneProperty value: "+myObject.OneProperty);
Console.WriteLine("SecondObject.OneMethod returned value: "+myObject.OneMethod(oneParameter));
}
Run Code Online (Sandbox Code Playgroud)
是否可以将FirstObject类型更改为SecondObject并继续使用它的属性和方法?
我已经超过总量控制FirstObject,但SecondObject被密封,完全从我的范围!
我可以通过反思实现这一目标吗 怎么样?您如何看待它可能需要做的工作?显然,这两个类都比上面的例子复杂得多.
这两个类都可以有类似的模板FirstObject<T>,SecondObject<T>这让我很难使用反射来完成这样的任务!
为了简单起见,我试图说明我的问题更简单,并尝试提取一些知识来解决它,但是,通过寻找答案,我觉得很明显,为了帮助我,你需要了解我的真正的问题,因为改变对象类型只是冰山一角.
我正在开发一个Workflow Definition API.主要目标是使API能够在我可能想要使用的任何引擎(CLR到WF4,NetBPM等)之上重复使用.
到现在为止,我正在编写中间层,将该API转换为WF4,以便通过CLR运行工作流程.
我已经完成了什么
在这个阶段,API概念在某种程度上类似于WF4,ActivityStates其中In/Out Arguments和Data(Variables)通过ActivityStates使用它们的参数运行.
伪代码中非常简化的API :
class Argument {
object Value;
}
class Data {
String Name;
Type ValueType;
object Value;
}
class ActivityState {
String DescriptiveName;
}
class MyIf: ActivityState {
InArgument Condition;
ActivityState Then;
ActivityState Else;
}
class MySequence: ActivityState {
Collection<Data> Data;
Collection<ActivityState> Activities;
}
Run Code Online (Sandbox Code Playgroud)
我最初将其转换为WF4的方法是在ActivitiesStates图表中运行并以某种方式直接分配属性,在需要时使用反射.
再次简化的伪代码,如:
new Activities.If() {
DisplayName=myIf.DescriptiveName,
Condition=TranslateArgumentTo_WF4_Argument(myIf.Condition),
Then=TranslateActivityStateTo_WF4_Activity(myIf.Then),
Else=TranslateActivityStateTo_WF4_Activity(myIf.Else)
}
new Activities.Sequence() {
DisplayName=mySequence.DescriptiveName,
Variables=TranslateDataTo_WF4_Variables(mySequence.Variables),
Activities=TranslateActivitiesStatesTo_WF4_Activities(mySequence.Activities)
}
Run Code Online (Sandbox Code Playgroud)
在翻译结束时,我将有一个可执行System.Activities.Activity对象.我已经轻松完成了这项工作.
最大的问题
当我开始翻译Data对象时,出现了这种方法的一个大问题System.Activities.Variable.问题是WF4将工作流程执行与上下文分开.因为这两者Arguments并Variables都LocationReferences必须通过访问var.Get(context)功能,为发动机知道他们是在运行时.
使用WF4可以轻松完成这样的事情:
Variable<string> var1=new Variable<string>("varname1", "string value");
Variable<int> var2=new Variable<int>("varname2", 123);
return new Sequence {
Name="Sequence Activity",
Variables=new Collection<Variable> { var1, var2 },
Activities=new Collection<Activity>(){
new Write() {
Name="WriteActivity1",
Text=new InArgument<string>(
context =>
String.Format("String value: {0}", var1.Get(context)))
},
new Write() {
//Name = "WriteActivity2",
Text=new InArgument<string>(
context =>
String.Format("Int value: {0}", var2.Get(context)))
}
}
};
Run Code Online (Sandbox Code Playgroud)
但如果我想通过我的API表示相同的工作流程:
Data<string> var1=new Data<string>("varname1", "string value");
Data<int> var2=new Data<int>("varname2", 123);
return new Sequence() {
DescriptiveName="Sequence Activity",
Data=new Collection<Data> { var1, var2 },
Activities=new Collection<ActivityState>(){
new Write() {
DescriptiveName="WriteActivity1",
Text="String value: "+var1 // <-- BIG PROBLEM !!
},
new Write() {
DescriptiveName="WriteActivity2",
Text="Int value: "+Convert.ToInt32(var2) // ANOTHER BIG PROBLEM !!
}
}
};
Run Code Online (Sandbox Code Playgroud)
当使用对象作为s 时,我最终遇到了一个大问题.我真的不知道如何允许开发人员使用我的API 在任何想要的地方使用对象(就像在WF4中一样),然后将其转换为.DataVariableDataDataSystem.Activities.Variable
如果你现在明白我的问题,FirstObject并且SecondObject是Data和System.Activities.Variable 分别.就像我说的翻译Data来Variable是冰山的一角,因为我可能会用Data.Get()在我的代码,不知道如何把它翻译成Variable.Get(context)一边做翻译.
我尝试或想过的解决方案:
解决方案1
相反性质的直接翻译过来的我会发展NativeActivites为每个流控制活动(If,Sequence,Switch,...)和使用CacheMetadata()功能来指定Arguments和Variables.问题仍然存在,因为它们都是通过访问var.Get(context).
解决方案2
给我的Data班级自己的Get()功能.它只是一个抽象的方法,没有内部逻辑,它会以某种方式转换为Get()函数System.Activities.Variable.这甚至可以使用C#吗?可能不会!另一个问题是a Variable.Get()有一个参数.
解决方案3
在最坏的解决方案,我认为是的CIL-manipulation.尝试将代码中Data/Argument使用的代码替换为Variable/Argument代码.这对我来说就像是一场噩梦.我几乎一无所知System.reflection.Emit,即使我学习它,我的猜测是它需要很长时间......甚至可能都不可能做到.
对不起,如果我最终引入了一个更大的问题,但我真的被困在这里,迫切需要一个提示/路径继续下去.
这被称为"鸭子打字"(如果它看起来像鸭子和像鸭子一样的嘎嘎叫,你可以在它上面调用方法,好像它真的是一只鸭子).将myObject声明为动态而不是特定类型,然后您应该好好去.
编辑:要明确,这需要.NET 4.0
dynamic myObject = new FirstObject();
// do stuff
myObject = new SecondObject();
// do stuff again