我有一系列实现接口的类。我想创建一个第三类(也实现接口),它将两个类的方法组合成一个,再加上一些管理代码。 换句话说。
假设我有这个界面:
public interface ITestClass
{
string NamePlusLastName(string name);
int AgePlus20(int age);
DateTime YearYouWillDie(int age);
}
我有两个实现它的类:
public class TestClassPeter : ITestClass
{
public string NamePlusLastName(string name)
{
return string.Concat(name, " ", "Mc.Cormick");
}
public int AgePlus20(int age)
{
return age + 40;
}
public DateTime YearYouWillDie(int age)
{
return DateTime.Now;
}
}
public class TestClassCharles : ITestClass
{
public string NamePlusLastName(string name)
{
return string.Concat(name, " ", "Gonzales");
}
public int AgePlus20(int age)
{
return age + 20;
}
public DateTime YearYouWillDie(int age)
{
return DateTime.Now ;
}
}
我想创建一个返回实现ITestClass的对象的类,其方法是两个类的组合。如:
public class TestBoth
{
ITestClass peter;
ITestClass charles;
ITestClass combinedClass;
public TestBoth()
{
// instantiate classes to be combined.
peter = new TestClassPeter();
charles = new TestClassCharles();
// BEG
// Add here code that will automatically combine methods of both classes into one.
// ......
// END
}
// expose as property
public ITestClass CombinedClass
{
get
{
return combinedClass;
}
}
}
所以最后我可以像这样调用组合类:
TestBoth classBuilder = new TestBoth();
ITestClass combinedClass = classBuilder.combinedClass;
// call a method
string fullName = combinedClass.NamePlusLastName("William");
幕后发生的事情真的是:
string firstValue = peter.NamePlusLastName("William");
// some code here
string secondValue = charles.NamePlusLastName("William");
// some more code here
return finalValue;
我希望所有方法都能自动执行此操作。这样,如果我更改了接口定义,以及Peter和Charles的实现,它将在classBuilder中自动修改。
答案 0 :(得分:0)
只需定义一个调用两个实现的第三个类,以某种方式组合它们的值并返回该结果,实现接口本身。我认为不需要 TestBoth ,除非你想动态构建代码,这是一种完全不同的方式,而且更加困难。我会做这样的事情:
public class TestClassPeterAndCharles : ITestClass
{
private readonly ITestClass peter;
private readonly ITestClass charles;
public TestClassPeterAndCharles()
{
// Create helper objects from base implementation
// Alternatively, take them as constructor parameters
this.peter = new TestClassPeter();
this.charles = new TestClassCharles();
}
public string NamePlusLastName(string name)
{
// Get the result from each class and operate on them
string namePeter = this.peter.NamePlusLastName(name);
string nameCharles = this.charles.NamePlusLastName(name);
return namePeter + nameCharles;
}
public int AgePlus20(int age)
{
int agePeter = this.peter.AgePlus20(age);
int ageCharles = this.charles.AgePlus20(age);
return agePeter + ageCharles;
}
public DateTime YearYouWillDie(int age)
{
DateTime yearPeter = this.peter.YearYouWillDie(age);
DateTime yearCharles = this.charles.YearYouWillDie(age);
return yearPeter + yearCharles;
}
}
答案 1 :(得分:0)
好的,经过一些研究和测试后,我认为我找到了一个可行的解决方案。它需要使用Unity Intercept和一些反射。
我将使用Unity创建其方法将被截获的类。我将该类默认为Peter,然后让CallHandler根据配置值确定从哪个类触发哪些方法。
首先,我定义了一个枚举,它将指定我希望使用的对象组合(Peter,Charles或Both):
public enum PersonChoice : byte
{
Peter = 1,
Charles = 2,
Both = 3
}
这将作为全局配置值。我将把它存放在彼得的财产中,这将是我将要拦截的类。所以我定义了属性并添加了一些构造函数逻辑。
public class TestClassPeter : ITestClass
{
private PersonChoice personChoice;
// Default Constructor
public TestClassPeter()
{
}
// Constructor where global personChoice is stored
public TestClassPeter(PersonChoice personChoice)
{
this.personChoice = personChoice;
}
public string NamePlusLastName(string name)
{
return string.Concat(name, " ", "Mc.Cormick");
}
public int AgePlus20(int age)
{
return age + 40;
}
public DateTime YearYouWillDie(int age)
{
return DateTime.Now;
}
public PersonChoice PersonChoice
{
get{return personChoice;}
}
}
我还需要向Charles添加一个默认构造函数:
public class TestClassCharles : ITestClass
{
public TestClassCharles()
{
}
...
}
我需要告诉界面定义Peter和Charles哪些方法会被截获。为此,我创建了一个Handler属性
public class ChoosePersonAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new PersonChoiceHandler();
}
}
然后将该属性应用于我的界面
public interface ITestClass
{
[ChoosePerson]
string NamePlusLastName(string name);
[ChoosePerson]
int AgePlus20(int age);
DateTime YearYouWillDie(int age);
}
接下来,我定义了一个类,它将为我提供一个准备被拦截的对象实例。 (注意容器有PersonChoice作为构造函数的参数)
public static class Arbitrator
{
public static ITestClass getInstance(PersonChoice personChoice)
{
// Initialize container
IUnityContainer unityContainer = new UnityContainer();
unityContainer.AddNewExtension<Interception>();
// Associate Interface with object to be intercepted
unityContainer.RegisterType<ITestClass, TestClassPeter>(new InjectionConstructor(personChoice));
unityContainer.Configure<Interception>()
.SetInterceptorFor<ITestClass>(new InterfaceInterceptor());
// return instance
return unityContainer.Resolve<ITestClass>();
}
}
现在,我创建了一种基于personChoice获取实例的外观
public class TestFacade
{
private ITestClass testClass;
public TestFacade(PersonChoice personChoice)
{
// Get Instance of primary object
ITestClass combinedClass = Arbitrator.getInstance(personChoice);
testClass = combinedClass;
}
// expose property
public ITestClass ITester
{
get
{
return testClass;
}
}
}
这是调用Handler代码。使用一些反射,我得到被调用方法的名称及其参数。使用全局personChoice参数我可以告诉这个处理程序实例化哪些类,然后决定(仲裁)要调用的方法。对于此示例,对于“Both”选项,我只是决定添加返回值。
public class PersonChoiceHandler : ICallHandler
{
private WriteOption writeOption;
private PersonChoice personChoice;
public PersonChoiceHandler(WriteOption writeOption)
{
this.writeOption = writeOption;
}
public PersonChoiceHandler()
{
this.writeOption = WriteOption.Both;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
// Get personChoice value from object property.
personChoice = (PersonChoice)Enum.Parse(typeof(PersonChoice), input.Target.GetType().GetProperty("PersonChoice").GetValue(input.Target, null).ToString());
// Get Method Name and parameters
string methodName = input.MethodBase.Name;
object[] methodArgs = new object[input.Inputs.Count];
for (int i = 0; i < input.Inputs.Count; i++)
{
methodArgs[i] = input.Inputs[i];
}
Type firstPersonType = null;
Type secondPersonType = null;
object firstPersonObject;
object secondPersonObject;
// based on personChoice value, instantiate appropriate class and execute the appropriate method .
switch (personChoice)
{
case PersonChoice.Peter:
firstPersonType = typeof(TestClassPeter);
break;
case PersonChoice.Charles:
firstPersonType = typeof(TestClassCharles);
break;
case PersonChoice.Both:
firstPersonType = typeof(TestClassPeter);
secondPersonType = typeof(TestClassCharles);
break;
default:
break;
}
// object is instantiated with default constructor. No need to specify PersonChoice property.
firstPersonObject = Activator.CreateInstance(firstPersonType);
if (personChoice == PersonChoice.Both)
{
secondPersonObject = Activator.CreateInstance(secondPersonType);
}
else
{
secondPersonObject = null; ;
}
// decide method invocation based on PersonChoice
object firstReturnValue;
object secondReturnValue;
switch (personChoice)
{
// Call Peter's or Charles' methods
case PersonChoice.Peter : case PersonChoice.Charles:
firstReturnValue = firstPersonType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, firstPersonObject, methodArgs);
break;
// Call Method on Both Peter and Charles and combine results
case PersonChoice.Both :
firstReturnValue = firstPersonType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, firstPersonObject, methodArgs);
secondReturnValue = secondPersonType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, secondPersonObject, methodArgs);
// build return value. Done here checking method name as an example.
if (methodName == "NamePlusLastName")
{
string returnValue = (string)firstReturnValue;
firstReturnValue = returnValue + (string)secondReturnValue;
}
else
{
int returnValue = (int)firstReturnValue;
firstReturnValue = returnValue + (int)secondReturnValue;
}
break;
default:
firstReturnValue = firstPersonType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, firstPersonObject, methodArgs);
break;
}
// Override initial method execution
IMethodReturn methodReturn = new VirtualMethodReturn(input, null);
// this down here would have called the original method.
//var methodReturn = getNext().Invoke(input, getNext);
// Set the return value
methodReturn.ReturnValue = firstReturnValue;
return methodReturn;
}
public int Order { get; set; }
}
以下是执行调用的示例程序:
class TestClass
{
static void Main()
{
// instantiate my facades
TestFacade peterFacade = new TestFacade(PersonChoice.Peter);
TestFacade charlesFacade = new TestFacade(PersonChoice.Charles);
TestFacade bothFacade = new TestFacade(PersonChoice.Both);
// run some methods:
// Peter
string name = "Peter";
int age = 15;
writeProperties(peterFacade, name, age);
// Charles
name = "Charles";
age = 20;
writeProperties(charlesFacade, name, age);
// Both
name = "Bothergate";
age = 234;
writeProperties(bothFacade, name, age);
// wait for user input.
Console.ReadLine();
}
static void writeProperties(TestFacade facade, string name, int age)
{
Console.WriteLine("Person name: {0} Last Name: {1} Age : {2} ", name, facade.ITester.NamePlusLastName(name), facade.ITester.AgePlus20(age));
}
}
最后,这是程序的输出:
姓名:Peter姓:Peter Mc.Cormick年龄:55
姓名:Charles姓:Charles Gonzales年龄:40
姓名:Bothergate姓:Bothergate Mc.CormickBothergate Gonzales年龄:528