如何解决在运行时保持功能更改对象类型
| 长话短说 说我有以下代码:// 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));
}
是否可以将“ 1”类型更改为“ 2”并继续使用其属性和方法?
我完全控制FirstObject
,但是Secondobject
已密封,完全超出了我的范围!
我可以通过反思来实现吗?怎么样?您如何看待要做的工作?显然,这两个类都比上面的示例复杂得多。
两个类都可以有FirstObject<T>
和Secondobject<T>
之类的模板,这让我感到难以使用反射来完成此类任务!
现实中的问题
为了简化起见,我试图以一种更简单的方式陈述我的问题,并尝试提取一些知识来解决它,但是,通过寻找答案,对我来说显而易见的是,要帮助我,您需要了解我真正的问题是,更改对象类型只是冰山一角。
我正在开发工作流程定义API。主要目标是使API能够在我可能要使用的任何引擎(CLR到WF4,NetBPM等)之上重用。
现在,我正在编写中间层,以将该API转换为WF4,以通过CLR运行工作流。
我已经完成的工作
在这个阶段,API概念与WF4相似,其中WF7具有with7ѭ,其中In / OutArguments
和Data
(Variables
)使用其参数贯穿through7ѭ。
伪代码中非常简化的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;
}
我最初将其转换为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)
}
翻译结束时,我将有一个可执行的System.Activities.Activity
对象。我已经很容易做到了。
大问题
当我开始将“ 9”对象转换为“ 17”时,这种方法出现了一个大问题。问题是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)))
}
}
};
但是如果我想通过我的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,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 !!
}
}
};
当将Data
对象用作Variable
时,我遇到了一个大问题。我真的不知道如何允许开发人员使用我的API在任何需要的地方使用Data
对象(就像WF4中一样),然后将Data
转换为System.Activities.Variable
。
解决方案浮现在脑海
如果您现在了解我的问题,FirstObject
和Secondobject
分别是Data
和System.Activities.Variable
。就像我说的那样,将ѭ9转换为ѭ25只是冰山一角,因为我可能在代码中使用ѭ35,并且在执行翻译时不知道如何将其转换为ѭ36。
我尝试过或想到的解决方案:
解决方案1
代替直接转换属性,我将为每个流控制活动(If
,Sequence
,Switch
,...)开发NativeActivites
,并利用CacheMetadata()
函数指定Arguments
和Variables
。问题仍然存在,因为它们都可以通过var.Get(context)
访问。
解决方案2
给我的Data
类自己的Get()
函数。它只是一个抽象方法,内部没有逻辑,它将以某种方式转换为ѭ17的Get()
函数。使用C#甚至可能吗?可能不会!另一个问题是ѭ49具有一个参数。
解决方案3
我想到的最糟糕的解决方案是50英镑。尝试将使用Data/Argument
的代码替换为Variable/Argument
代码。这对我来说就像一场噩梦。我对ѭ53几乎一无所知,即使我了解了它,我的猜测也是要花很多时间……甚至可能做不到。
抱歉,如果我最终提出了一个更大的问题,但是我真的被困在这里,迫切需要小费/继续前进的道路。
解决方法
这被称为“鸭子打字”(如果它看起来像鸭子,而象鸭子一样的嘎嘎叫声,则可以像在鸭子上一样调用它的方法)。将myObject声明为动态的,而不是特定的类型,然后您应该会很好。
编辑:要清楚,这需要.NET 4.0
dynamic myObject = new FirstObject();
// do stuff
myObject = new SecondObject();
// do stuff again
,反思并不一定是正确的任务。如果无法控制SecondObject
,则最好的选择可能只是使用扩展方法实例化该文件的新副本,然后逐个属性地复制数据。
您可以在复制过程中使用反射,然后以这种方式工作,但这确实是一个单独的问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。