C#中模板类型中的必需属性

时间:2011-05-08 09:57:02

标签: c# generics

考虑到通用方法,是否有可能在模板类型上设置约束以具有某些特定属性?

为了成功编译以下代码,例如

public static int[] DoSomething<T> (T[] Input)
{
   int[] Output = new int[Input.Length];

   for (int i = 0;i < Input.Length;i++)
      Output[i] = (int)Input[i].PropertyA+(int)Input[i].PropertyB;

   return Output;
}

模板类型需要实现PropertyA和PropertyB。 有可能以某种方式在模板类型上设置这样的约束吗?

修改: 并且还要求PropertyA和PropertyB是数字类型,因此可以将它们键入int。

感谢。

2 个答案:

答案 0 :(得分:5)

唯一的可能性是将T定义为从一些众所周知的基类派生的类型或实现众所周知的接口:

public interface IWellKnown
{
   int PropertyA { get; }
   int PropertyB { get; }
}

您的任何方法都是:

public static int[] DoSomething<T> (T[] Input) where T : IWellKnown
{
   int[] Output = new int[Input.Length];

   for (int i = 0;i < Input.Length;i++)
      Output[i] = Input[i].PropertyA+Input[i].PropertyB;

   return Output;
}

编辑:

创建使用任何数字类型但只使用数字类型的泛型方法是不可能的,因为.NET没有像Number这样的基类型。因此,您不能仅将通用类型限制为数字。所有数字类型都是值类型,因此您可以执行以下操作:

public interface IWellKnown<TData> where TData : struct
{
    TData PropertyA { get; }
    TData PropertyB { get; }
}

但在这种情况下,您的界面将接受任何值类型 - 任何自定义结构,char,bool等。

答案 1 :(得分:0)

不可能创造这样的限制。您应该在运行时检查输入并抛出一个有用的异常错误消息。

但你可以这样做:

public interface IWellKnown
{
   int PropertyA { get; }
   int PropertyB { get; }
}

public abstract class WellKnownBase<T> : IWellKnown
{
   IWellKnown.PropertyA { get { return Convert(this.PropertyA); } }
   IWellKnown.PropertyB { get { return Convert(this.PropertyB); } }

   public T PropertyA { get; }
   public T PropertyA { get; }

   protected virtual int Convert(T input) { return (int)input; }
}

使用这样的基类引导实现具体版本的基类提供一种转换为int的方法。显式接口实现提供对int类型访问器的访问,而“真实”类仍提供原始类型。

public class WellKnownFloat : WellKnownBase<Float> {}

会为你提供一个浮动类。如果类型不能转换为int,则可以提供自定义转换器:

public class WellKnownTimeSpan : WellKnownBase<TimeSpan>
{
    protected override int Convert(TimeSpan input) 
    { 
        return (int)input.TotalMilliseconds; 
    }
}

顺便说一下,使用linq并将需求添加到界面中,您可以将函数重写为input.Select(x => x.PropertyA + x.PropertyB)).ToArray()

PS:请使用VisualStudio检查代码,我只是在没有编译器支持的情况下编写代码;)可能存在小的编译时错误。