在C#中使用`where T:SOMETHING`构造

时间:2009-06-04 10:04:43

标签: c# generics

刚刚在这里找到了一些代码来编写访问某些数据库实体的代码......

public static OurCustomObject GetOurCustomObject(int primaryKey)
{
    return GetOurCustomObject<int>(primaryKey, "usp_GetOurCustomObjectByID");
}

public static OurCustomObject GetOurCustomObject(Guid uniqueIdent)
{
    return GetOurCustomObject<Guid>(uniqueIdent, "usp_GetOurCustomObjectByGUID");
}

private static OurCustomObject<T>(T identifier, string sproc)
{

    if((T != typeof(int)) && (T == typeof(Guid)))
    {
        throw new ArgumentException("Identifier must be a string or an int");
    }

    //ADO.NET Code to make DB Call with supplied sproc.
}

Theres就是它的一些东西似乎不是generic。这个事实 sprocs传入内部方法感觉很难看。但我能看到的唯一方法就是在

的私有方法中使用if / else
if(type == int)
    sproc = "GetByID";
else if (type == Guid)
    sproc = "GetByGUID";

同样抛出的异常看起来也很丑......无论如何都要使用where T:clause

e.g。

private static OurCustomObject<T>(T identifier) where T : int OR Guid

有关如何清理这一点的任何建议。

4 个答案:

答案 0 :(得分:8)

你不能指定一个约束,上面写着“它是这两个中的一个”,没有。

可以做的是:

Dictionary<Type, string> StoredProcedureByType = new Dictionary<Type, string>
{
    { typeof(Guid), "GetByGUID" },
    { typeof(int), "GetByID" }
};

然后使用:

string sproc;
if (!StoredProcedureByType.TryGetValue(typeof(T), out sproc))
{
    throw new ArgumentException("Invalid type: " + typeof(T).Name);
}

这对于几种类型来说可能有点过头了,但如果涉及很多类型,它可以很好地扩展。

鉴于这两种类型都是值类型,您可以使用以下约束使其成为更强大:

where T : struct

但仍然允许byte等。

答案 1 :(得分:2)

您提供的代码看起来相当不错,因为private static OurCustomObject<T>(T identifier, string sproc)是私有的。我甚至会从这个方法中删除异常检查,因为再次 - 它是私有的,所以这个类控制传递给方法的内容。 if语句会相当可怕并且过度设计。

答案 2 :(得分:1)

最重要的事情可能就是做这样的事情:

public interface IPrimaryKey 
{
}

public class PrimaryGuidKey(Guid key) : IPrimaryKey 

public class PrimaryIntegerKey(int key) : IPrimaryKey

private static OurCustomObject<T>(T identifier) where T : IPrimaryKey

答案 3 :(得分:0)

不支持这样的where子句以这种方式限制类型参数(不幸的是)。

在这种情况下,您可能会发现将identifier作为对象传递,而使用泛型传递而不是实际上更清晰(当我需要类似的东西时,这就是我最终做的事情:似乎是最差的方法)。

这是一个C#弱的领域,既不是动态语言,也不能专门化模板(像C ++一样,只提供T = int和T = Guid的实现)。

Adendum:在这种情况下,我可能会坚持使用重载,但是将类型检查更改为Assert,因为这是一种私有帮助方法。