有没有一种方法,我可以强制遵循一定的方法签名的方法?
-
20-08-2019 - |
题
让我们说我有
public delegate DataSet AutoCompleteDelegate(
string filter, long rowOffset);
我可以进行以下类执行这一方法的签名? (只是一个唤起了主意):
public class MiddleTier
{
[Follow(AutoCompleteDelegate)]
public DataSet Customer_AutoComplete(string filter, long rowOffset)
{
var c = Connect();
// some code here
}
[Follow(AutoCompleteDelegate)]
public DataSet Item_AutoComplete(string filter, long rowOffset)
{
var c = Connect();
// some code here
}
// this should give compilation error, doesn't follow method signature
[Follow(AutoCompleteDelegate)]
public DataSet BranchOffice_AutoComplete(string filter, string rowOffset)
{
var c = Connect();
// some code here
}
}
[编辑]
目的:我已经把我的middletier的方法属性。我有这样的方法:
public abstract class MiddleTier : MarshalByRefObject
{
// Operation.Save is just an enum
[Task("Invoice", Operation.Save)]
public Invoice_Save(object pk, DataSet delta);
[Task("Receipt", Operation.Save)]
public Receipt_Save(object pk, DataSet delta);
// compiler cannot flag if someone deviates from team's standard
[Task("Receipt", Operation.Save)]
public Receipt_Save(object pk, object[] delta);
}
然后在运行时,我会遍历所有middletier的方法,并把它们集合(属性有很大帮助,在这里),然后在WinForm的的委托功能将它们映射(通过接口方便,插件为基础的系统)作为加载
我在想,如果我可以让属性的更多自描述的,所以编译器可以赶上不一致。
namespace Craft
{
// public delegate DataSet SaveDelegate(object pk, DataSet delta); // defined in TaskAttribute
public abstract class MiddleTier : MarshalByRefObject
{
[Task("Invoice", SaveDelegate)]
public abstract Invoice_Save(object pk, DataSet delta);
[Task("Receipt", SaveDelegate)]
// it's nice if the compiler can flag an error
public abstract Receipt_Save(object pk, object[] delta);
}
}
我在想,如果把每一类的方法,这将是一个矫枉过正总是实例化一个远程对象。并把它们放在单独的类,它可能是更难方便代码重用,让我们说Invoice_Save需要对Receipt_Open一些信息。事实上,我甚至这里有一个报告(水晶),其获取来自远程处理middletier DataSet中的数据,被调用的方法中,它得到其他方法的一些信息,并在自己的DataSet合并,它们都发生在middletier,没有几个往返,所有都在服务器端进行(中间层)
解决方案
您可以同时实现你在你的榜样和写一个静态分析的FollowAttribute
(比方说,的FxCop)规则,可以检查是否是标记有属性的任何方法具有相同的签名提到委托。因此,它应该是可能的。
其他提示
其他答案显然是有效的,但什么都不会保护你对忘记你的方法适用[Follow(AutoCompleteDelegate)]
属性。
我想你会过得更好使转向方法成实现接口的类:
public interface IAutoComplete
{
DataSet Complete(string filter, long rowOffset);
}
public class CustomerAutoComplele : IAutoComplete
{
public DataSet Complete(string filter, long rowOffset)
{
var c = Connect();
// some code here
}
}
然后使用工厂方法模式来让你的“自动完成者”:
public static class AutoCompleteFactory
{
public static IAutoComplete CreateFor(string purpose)
{
// build up and return an IAutoComplete implementation based on purpose.
}
}
或
public static class AutoCompleteFactory
{
public static IAutoComplete CreateFor<T>()
{
// build up and return an IAutoComplete implementation based on T which
// could be Customer, Item, BranchOffice class.
}
}
一旦你有,你可以看看控制和依赖注入的反转,以避免硬编码在你的工厂方法自动完成实现的列表。
这是不是一种语言功能,但...
这是你可以做的验证为:编写单元测试,反映了阶级和失败,如果签名不匹配属性声明
PostSharp 也给你周边的编译这样做了一些有趣的选项。我不知道你会如何准确地使用它,但我怀疑你能...
我会质疑为什么你要做到这一点。如果你不希望类通过继承而改变,你可以把它密封类。如果你担心有人改变未来的类,你有两种情况1。 1)他们不明白他们在做什么;没有什么可以阻止坏的程序员从做不好的事情,如果他们有充分的在位编辑程序文本。 2)他们的方式,你目前不明白这会伤害重用扩展类的功能。
属性被存储为在编译过程中额外的元信息 - 你可以在运行时对它们进行查询,但在编译过程中它们不在因素
可以不通过在其上的属性约束的方法。可以限制属性是如何应用的(一个以上即,仅关于方法,或是否可以应用)。
我会建议使用FxCop的警告时,属性不匹配 - 如果你不小心的方式对事件的支持类型转换:
[Follow(AutoCompleteDelegate)]
public DataSet Customer_AutoComplete(string filter, int rowOffset)
将是一个有效的委托。
没有
排序的。
您不能得到在编译时这种行为。可以,具有属性,该推入一个简单的测试工具或强制当含类被实例化立即失效。
考虑两个(快速黑客攻击)属性:
[AttributeUsage(AttributeTargets.Class)]
public class EnforceConforms : Attribute
{
public EnforceConforms(Type myClass)
: base()
{
MethodInfo[] info = myClass.GetMethods();
foreach (MethodInfo method in info)
{
object[] objs = method.GetCustomAttributes(false);
foreach (object o in objs)
{
Attribute t = (Attribute)o;
if (t.GetType() != typeof(ConformsAttribute)) continue;
MethodInfo mustConformTo = ((ConformsAttribute)t).ConformTo;
ParameterInfo[] info1 = mustConformTo.GetParameters();
ParameterInfo[] info2 = method.GetParameters();
bool doesNotCoform = false;
doesNotCoform |= (mustConformTo.ReturnType != method.ReturnType);
doesNotCoform |= (info1.Length != info2.Length);
if (!doesNotCoform)
{
for (int i = 0; i < info1.Length; i++)
{
ParameterInfo p1 = info1[i];
ParameterInfo p2 = info2[i];
if (!p1.ParameterType.Equals(p2.ParameterType))
{
doesNotCoform = true;
break;
}
}
}
if (doesNotCoform)
{
throw new Exception(myClass.Name + "." + method.Name + " does not conform to required delegate signature");
}
}
}
}
}
[AttributeUsage(AttributeTargets.Method)]
public class ConformsAttribute : Attribute
{
public MethodInfo ConformTo;
public ConformsAttribute(Type type)
: base()
{
if (type.BaseType != typeof(Delegate) && type.BaseType != typeof(System.MulticastDelegate)) throw new Exception("Can only accept delegates");
ConformTo = type.GetMethod("Invoke");
}
}
投掷EnforceConforms(typeof运算(myFavoriteClass))到一个类,并且符合(typeof运算(myFavoriteDelegate))到所述相关的方法和然后的(这是哈克部分)的typeof(myFavoriteClass).GetCustomAttributes(假)。你可以在一个静态初始化这样做失败“真快”或者在测试类这样做(这会在大会的所有方法与EnforceConforms属性,如果你想获得幻想)。
一般情况下,你可能不应该使用这个。如果您的设计需要您检查适当的委托实现你应该尽可能重新构建。另外它的非编译时位使它所以你没有真正为自己节省很多的时间的方式。