C# 是否可以将委托作为属性参数?
是否可以将委托作为属性的参数 像这样:C# 是否可以将委托作为属性参数?,c#,delegates,custom-attributes,C#,Delegates,Custom Attributes,是否可以将委托作为属性的参数 像这样: public delegate IPropertySet ConnectionPropertiesDelegate(); public static class TestDelegate { public static IPropertySet GetConnection() { return new PropertySetClass(); } } [AttributeUsage(AttributeTargets
public delegate IPropertySet ConnectionPropertiesDelegate();
public static class TestDelegate
{
public static IPropertySet GetConnection()
{
return new PropertySetClass();
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface,AllowMultiple=false,Inherited=true)]
public class WorkspaceAttribute : Attribute
{
public ConnectionPropertiesDelegate ConnectionDelegate { get; set; }
public WorkspaceAttribute(ConnectionPropertiesDelegate connectionDelegate)
{
ConnectionDelegate = connectionDelegate;
}
}
[Workspace(TestDelegate.GetConnection)]
public class Test
{
}
如果不可能,有哪些合理的替代方案?不,不能将委托作为属性构造函数参数。请参阅可用类型:
作为一种解决方法(尽管它是黑客和容易出错的),您可以创建:
其他可能的解决方法是使用与委托定义匹配的抽象方法创建抽象基本属性类型,然后在具体属性类中实现该方法 它有以下好处:
- 注释更加简洁和清晰(类似DSL)
- 不思考
- 易于重用
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple=false, Inherited=true)]
public abstract class GetConnectionAttribute : Attribute
{
public abstract IPropertySet GetConnection();
}
public class GetConnectionFromPropertySetAttribute : GetConnectionAttribute
{
public override IPropertySet GetConnection()
{
return new PropertySetClass();
}
}
[GetConnectionFromPropertySet]
public class Test
{
}
我通过使用枚举和代理映射数组解决了这个问题。虽然我非常喜欢使用继承的想法,但在我的场景中,这需要我编写几个子类来完成相对简单的工作。这也应该是可重构的。唯一的缺点是,必须确保数组中代理的索引与枚举值相对应
public delegate string FormatterFunc(string val);
public enum Formatter
{
None,
PhoneNumberFormatter
}
public static readonly FormatterFunc[] FormatterMappings = { null, PhoneNumberFormatter };
public string SomeFunction(string zzz)
{
//The property in the attribute is named CustomFormatter
return FormatterMappings[(int)YourAttributeHere.CustomFormatter](zzz);
}
巫术。在接受的答案上增加,以使用动态委托类型:
namespace NetStandardReporting
{
// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public class DynamicDllImportAttribute
: System.Attribute
{
protected string m_name;
public string Name
{
get
{
return this.m_name;
}
}
public DynamicDllImportAttribute(string name)
: base()
{
this.m_name = name;
}
private static System.Type CreateDelegateType(System.Reflection.MethodInfo methodInfo)
{
System.Func<System.Type[], System.Type> getType;
bool isAction = methodInfo.ReturnType.Equals((typeof(void)));
System.Reflection.ParameterInfo[] pis = methodInfo.GetParameters();
System.Type[] types = new System.Type[pis.Length + (isAction ? 0: 1)];
for (int i = 0; i < pis.Length; ++i)
{
types[i] = pis[i].ParameterType;
}
if (isAction)
{
getType = System.Linq.Expressions.Expression.GetActionType;
}
else
{
getType = System.Linq.Expressions.Expression.GetFuncType;
types[pis.Length] = methodInfo.ReturnType;
}
return getType(types);
}
private static System.Delegate CreateDelegate(System.Reflection.MethodInfo methodInfo, object target)
{
System.Type tDelegate = CreateDelegateType(methodInfo);
if(target != null)
return System.Delegate.CreateDelegate(tDelegate, target, methodInfo.Name);
return System.Delegate.CreateDelegate(tDelegate, methodInfo);
}
// protected delegate string getName_t();
public DynamicDllImportAttribute(System.Type classType, string delegateName)
: base()
{
System.Reflection.MethodInfo mi = classType.GetMethod(delegateName,
System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic
);
// getName_t getName = (getName_t)System.Delegate.CreateDelegate(delegateType, mi));
System.Delegate getName = CreateDelegate(mi, null);
object name = getName.DynamicInvoke(null);
this.m_name = System.Convert.ToString(name);
}
} // End Class DynamicDllImportAttribute
public class DynamicDllImportTest
{
private static string GetFreetypeName()
{
if (System.Environment.OSVersion.Platform == System.PlatformID.Unix)
return "libfreetype.so.6";
return "freetype6.dll";
}
// [DynamicDllImportAttribute("freetype6")]
[DynamicDllImportAttribute(typeof(DynamicDllImportTest), "GetFreetypeName")]
public static string bar()
{
return "foobar";
}
// NetStandardReporting.DynamicDllImportTest.Test();
public static void Test()
{
System.Reflection.MethodInfo mi = typeof(DynamicDllImportTest).GetMethod("bar",
System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic);
object[] attrs = mi.GetCustomAttributes(true);
foreach (object attr in attrs)
{
DynamicDllImportAttribute importAttr = attr as DynamicDllImportAttribute;
if (importAttr != null)
{
System.Console.WriteLine(importAttr.Name);
}
} // Next attr
} // End Sub Test
} // End Class
} // End Namespace
名称空间NetStandardReporting
{
//[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface,AllowMultiple=false,Inherited=true)]
公共类动态AllImportAttribute
:System.Attribute
{
受保护的字符串m_名称;
公共字符串名
{
得到
{
返回此.m_名称;
}
}
公共DynamicDLImportAttribute(字符串名称)
:base()
{
this.m_name=名称;
}
私有静态System.Type CreateDelegateType(System.Reflection.MethodInfo MethodInfo)
{
System.Func getType;
bool isAction=methodInfo.ReturnType.Equals((typeof(void));
System.Reflection.ParameterInfo[]pis=methodInfo.GetParameters();
System.Type[]types=新的System.Type[pis.Length+(isAction?0:1)];
对于(整数i=0;i
实际上这是一个很好的解决方法。我已经为此构建了一个特殊的接口,但是委托要简单得多。谢谢这是一个解决办法,但不是一个好办法。这正是@nemesv所说的——黑客和容易出错,因为如果您使用重构菜单将方法GetConnection的名称更改为其他名称,字符串“GetConnection”将不会自动更改。那么在c#中是否有可能手动限制构造函数类型的参数?我没听说过什么,但正如我们在Attribute
type中看到的,这是可能的。怎么做?这个限制直接建立在语言规范的内部。因此,您不能对自定义类型执行相同的操作,因为它只处理属性。值得注意的是,现在使用C#6,您可以执行:[Workspace(typeof(TestDelegate),nameof(TestDelegate.GetConnection))],这似乎可以解决由于重构而容易出错的问题
namespace NetStandardReporting
{
// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public class DynamicDllImportAttribute
: System.Attribute
{
protected string m_name;
public string Name
{
get
{
return this.m_name;
}
}
public DynamicDllImportAttribute(string name)
: base()
{
this.m_name = name;
}
private static System.Type CreateDelegateType(System.Reflection.MethodInfo methodInfo)
{
System.Func<System.Type[], System.Type> getType;
bool isAction = methodInfo.ReturnType.Equals((typeof(void)));
System.Reflection.ParameterInfo[] pis = methodInfo.GetParameters();
System.Type[] types = new System.Type[pis.Length + (isAction ? 0: 1)];
for (int i = 0; i < pis.Length; ++i)
{
types[i] = pis[i].ParameterType;
}
if (isAction)
{
getType = System.Linq.Expressions.Expression.GetActionType;
}
else
{
getType = System.Linq.Expressions.Expression.GetFuncType;
types[pis.Length] = methodInfo.ReturnType;
}
return getType(types);
}
private static System.Delegate CreateDelegate(System.Reflection.MethodInfo methodInfo, object target)
{
System.Type tDelegate = CreateDelegateType(methodInfo);
if(target != null)
return System.Delegate.CreateDelegate(tDelegate, target, methodInfo.Name);
return System.Delegate.CreateDelegate(tDelegate, methodInfo);
}
// protected delegate string getName_t();
public DynamicDllImportAttribute(System.Type classType, string delegateName)
: base()
{
System.Reflection.MethodInfo mi = classType.GetMethod(delegateName,
System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic
);
// getName_t getName = (getName_t)System.Delegate.CreateDelegate(delegateType, mi));
System.Delegate getName = CreateDelegate(mi, null);
object name = getName.DynamicInvoke(null);
this.m_name = System.Convert.ToString(name);
}
} // End Class DynamicDllImportAttribute
public class DynamicDllImportTest
{
private static string GetFreetypeName()
{
if (System.Environment.OSVersion.Platform == System.PlatformID.Unix)
return "libfreetype.so.6";
return "freetype6.dll";
}
// [DynamicDllImportAttribute("freetype6")]
[DynamicDllImportAttribute(typeof(DynamicDllImportTest), "GetFreetypeName")]
public static string bar()
{
return "foobar";
}
// NetStandardReporting.DynamicDllImportTest.Test();
public static void Test()
{
System.Reflection.MethodInfo mi = typeof(DynamicDllImportTest).GetMethod("bar",
System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic);
object[] attrs = mi.GetCustomAttributes(true);
foreach (object attr in attrs)
{
DynamicDllImportAttribute importAttr = attr as DynamicDllImportAttribute;
if (importAttr != null)
{
System.Console.WriteLine(importAttr.Name);
}
} // Next attr
} // End Sub Test
} // End Class
} // End Namespace