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

C# 在C中使用'where T:SOMETHING'构造#,c#,generics,C#,Generics,刚刚发现了一些代码,这里有人写了一些代码来访问一些数据库实体 public static OurCustomObject GetOurCustomObject(int primaryKey) { return GetOurCustomObject<int>(primaryKey, "usp_GetOurCustomObjectByID"); } public static OurCustomObject GetOurCustomObject(Guid uniqueIdent

刚刚发现了一些代码,这里有人写了一些代码来访问一些数据库实体

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.
}
此外,异常抛出看起来也很难看。。。是否仍然需要使用where T:子句

e、 g

私有静态自定义对象(T标识符),其中T:int或Guid

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

您不能指定一个表示“这是这两个约束之一”的约束,否

你能做的是:

对于一些类型来说,这可能是过分的,但是如果涉及到很多类型,那么它的伸缩性就很好

鉴于这两种类型都是值类型,您可以通过以下约束使其更加健壮:

where T : struct

但这仍然允许
byte
等。

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

在这种情况下,您可能会发现将
标识符作为对象传递,而不使用泛型实际上更干净(当我需要类似的东西时,这就是我最终要做的:似乎是最不糟糕的方法)

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


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

您提供的代码在我看来相当不错,因为
私有静态OurCustomObject(T标识符,字符串存储过程)
是私有的。我甚至会从这个方法中删除异常检查,因为它是私有的,所以这个类控制传递给这个方法的内容。if语句将是相当可怕和过度设计的。

最整洁的做法可能是这样做:

public interface IPrimaryKey 
{
}

public class PrimaryGuidKey(Guid key) : IPrimaryKey 

public class PrimaryIntegerKey(int key) : IPrimaryKey

private static OurCustomObject<T>(T identifier) where T : IPrimaryKey
公共接口IPrimaryKey
{
}
公共类PrimaryGuidKey(Guid键):IPrimaryKey
公共类PrimaryIntegerKey(int-key):IPrimaryKey
私有静态OurCustomObject(T标识符),其中T:IPrimaryKey

泛型类型不是模板,也不打算成为模板。人们可以提出C++模板是“弱”的理由,因为与泛型类型不同,在模板被编译成库之后,它们不能用新的类型参数构造。但这将是一个愚蠢的论点;简单的事实是,泛型和模板虽然在文本上表面上相似,但实际上有着非常不同的语义和解决不同的问题。@Eric:是的,但这并不意味着专业化确实会有所帮助。你在方法体中使用“T”的目的是什么?仅此而已,它没有被专门使用。有一个typeof(T)=typeof(int)检查,然后他们使用一个SQL助手调用执行存储过程,并将标识符作为参数传递。这就是为什么当我同意你的观点,这似乎是一个糟糕的设计时,我觉得使用起来有点强迫。泛型方法的目的是,嗯,泛型。一个只能是两件事的“泛型”不是很泛型。如果您没有将T用于其他任何东西,那么您唯一可能使用的就是“标识符”——一个不受约束的T——因为在主体中是作为System.Object的。为什么不完全消除泛型,只将“标识符”作为一个对象呢?
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
public interface IPrimaryKey 
{
}

public class PrimaryGuidKey(Guid key) : IPrimaryKey 

public class PrimaryIntegerKey(int key) : IPrimaryKey

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