提问人:sbi 提问时间:10/7/2010 最后编辑:sbi 更新时间:10/8/2010 访问量:271
概括需要处理不同数据成员的算法
Generalize an algorithm that needs to work on different data members
问:
我有一段代码是这样的:
void someAlgorithm(SomeType someVar)
{
someVar.someMember = createSomeValue();
lock(something)
{
SomeType someOtherVar = something.Find(someVar.unrelatedMember);
if(someOtherVar != null)
someOtherVar.someMember = someVar.someMember;
}
}
(我需要稍微调整一下才能发布,所以如果我搞砸了,请耐心等待。
现在,我需要为另一个成员(具有相关但不同的类型)和另一个创建函数提供这段确切的代码。我知道我可以获取此代码,复制它,替换一些标识符,然后完成。但我觉得这样做很脏。我觉得应该有一种方法来推广这个小算法。someVar
我知道我总是可以将创建函数作为委托传递,但我不知道如何概括成员访问权限,然后是这些成员(和创建函数)具有不同类型的问题。
在 C++ 中,我会使用成员指针和模板来执行此操作。成员指针并不是小菜一碟,但是一旦我查找了它们奇怪的语法,我就会在几分钟内完成。如何在C#中做到这一点?
编辑:由于这似乎还不够清楚,因此下面是同一算法的其他实例的样子:
void someOtherAlgorithm(SomeOtherType someVar) // 1 change here
{
someVar.someOtherMember = createSomeOtherValue(); // 2 changes here
lock(something)
{
SomeOtherType someOtherVar = something.Find(someVar.unrelatedMember);
if(someOtherVar != null)
someOtherVar.someOtherMember = someVar.someOtherMember; // 2 changes here
}
}
我希望这能澄清这一点。
答:
您可以传递用于创建和设置值的 lambda 表达式。
例如:
void someAlgorithm<TObject, TProperty>(TObject someVar, Func<TProperty> creator, Action<TObject, TProperty> setter, Action<SomeType, TProperty> relatedSetter)
{
var value = creator();
setter(someVar, value);
lock(something)
{
var someOtherVar = something.Find(someVar.SomeOtherMember);
if(someOtherVar != null)
relatedSetter(someOtherVar, value);
}
}
someAlgotihm(something, createSomeValue, (x, v) => x.someProperty = v, (x, v) => x.someProperty = v);
评论
someOtherVar.someMember = someVar.someMember;
someOtherVar
someVar.SomeOtherMember
someVar
TObject
TObject
我认为最好的选择是使用委托并将一个简单的选择器函数作为参数传递给算法。可以使该方法泛型,以便选择器可以返回任何类型的成员:Func
void someAlgorithm<T>(SomeType someVar, SomeType someOtherVar,
Func<SomeType, T> selector) {
someVar.someMember = createSomeValue();
lock(something) {
var someOtherVar = something.Find(selector(someVar)); // Use 'selector'
if(someOtherVar != null)
someOtherVar.someMember = someVar.someMember;
}
}
然后你可以写这样的东西:
someAlgorithm(some1, some2, a => a.SomeOtherMember);
如果没有关于实际代码的更多细节,就很难精确地写出答案(例如,您可能需要对泛型类型参数进行一些约束 - 例如 如果要比较这些值),但这通常是解决问题的最佳方法。IComparable
如果您需要在设置/获取值的代码中进行另一个参数化,那么您只需添加其他函数即可。例如(设置值)和另一个成员的“选择器”函数。在调用中,这将是 .如果具有不同的类型,则可能需要再添加一个类型参数。someMember
Action<SomeType, T>
(s, val) => s.SomeMember = val
someMember
评论
someMember
someOtherMember
你让我有点困惑,那里。你接受一个调用类型的参数,并声明一个同名的局部变量(所以它不能按原样编译)。从你的两个定义来看,和似乎是相同的类型(),但你的局部变量只用 声明,所以不完全清楚它们是否是。someAlgorithm
SomeType
someOtherVar
someVar
someOtherVar
SomeType
var
在你对 SLaks 的评论中,你暗示了 和 是不同的类型(即使在你引用的问题部分,你说的是不同的成员,而 SLaks 问的是你的两个变量和)。因此,我将假设它们是不同的类型,这只是一个局部变量,而不是参数。someVar
someOtherVar
someVar
someVar
someOtherVar
someOtherVar
基于这些假设:
void someAlgorithm<TMember>(
SomeType someVar,
Func<TMember> create, // replaces "createSomeValue"
Func<SomeType, TMember> getter, // replaces get for "someMember"
Action<SomeType, TMember> setter, // replaces set for "someMember"
Action<SomeOtherType, TMember> setter2) // replaces set for "someMember"
// on "someOtherVar" (not necessary
// if "someOtherVar" is actually
// the same type as "someVar")
{
setter(somevar, create());
lock(something)
{
SomeOtherType someOtherVar = something.Find(someVar.unrelatedMember);
if(someOtherVar != null)
setter2(someOtherVar, getter(someVar));
}
}
对于您的第一个算法,这将称为:
someAlgorithm(
someVar,
createSomeValue,
x => x.someMember,
(x, y) => { x.someMember = y; },
(x, y) => { x.someMemberOfOtherType = y; }
);
对于您的第二个:
someAlgorithm(
someVar,
createSomeOtherValue,
x => x.someOtherMember,
(x, y) => { x.someOtherMember = y; },
(x, y) => { x.someOtherMemberOfOtherType = y; }
);
评论
+1
:(
SomeType
SomeType
评论
someMember
someOtherMember
createSomeValue()
createSomeOtherValue()
someOtherVar
someVar