我目前正在尝试在我的类定义中实现“索引”属性。
例如,我有以下课程:
public class TestClass
{
private int[] ids = null;
public string Name { get; set; }
public string Description { get; set; }
public int[] Ids {
get
{
//Do some magic and return an array of ints
//(count = 5 - in this example in real its not fixed)
return _ids;
}
}
}
现在我喜欢将此类用作以下内容:
private void DoSomething()
{
var testClass = GetSomeTestClass();
//work with the ids
for (int i = 0; i < 10; i++) //I know I could say i < Ids.Length, its just an example
{
int? id = testClass.Ids[i];
//this will result, in a out of bound exception when i reaches 5 but I wish for it to return a null like a "safe" index call ?!?
}
}
所以有一个安全的索引调用导致null,而不需要我在try catch中再次包装它。
我不希望使用类索引的另一件事,因为我需要几个像这样工作的属性,具有不同的类型(int,string,bool,custom class等)。
(再一次,只是一个简单的例子,我知道在这种情况下我可以说“我&lt; Ids.Length”)
答案 0 :(得分:6)
如果您只对已经不可为空的类型数据感兴趣,例如struct
您可以使用简单的扩展方法,例如
public static class ArrayExt
{
public static Nullable<T> GetValueOrNull(this T[] array, int index) where T: struct
{
return array.Length < index ? new Nullable<T>(array[index]) : null;
}
}
这会让你简单地调用
int? id = testClass.Ids.GetValueOrNull(i);
但是,鉴于你需要支持任意数量的类型,我的建议是在数组周围实现一个包装,并控制你如何访问数据,例如。
public class SafeArray<T>
{
private T[] items;
public SafeArray(int capacity)
{
items = new T[capacity];
}
public object this[int index]
{
get
{
return index < items.Length ? (object)items[index] : null;
}
set
{
items[index] = (T)value;
}
}
}
public class TestClass
{
public TestClass()
{
Ids = new SafeArray<int>(5);
Instances = new SafeArray<MyClass>(5);
}
...
public SafeArray<int> Ids { get; private set; }
public SafeArray<MyClass> Instances { get; private set; }
}
这种方法的关键是使用object
作为返回类型。这允许您将数据(或盒子/ unbox,如果使用值类型)转换为接收端的预期类型,例如。
for (int i = 0; i < 10; i++)
{
// we need an explicit cast to un-box value types
var id = (int?)testClass.Ids[i];
// any class is already of type object so we don't need a cast
// however, if we want to cast to original type we can use explicit variable declarations e.g.
MyClass instance = testClass.Instances[i];
}
答案 1 :(得分:2)
好的,全新的方法。由于您有几种可能的类型并且需要“joker”方法,因此您可以将值存储为类中的键/值集合,然后可以使用此方法。
首先,在内部存储值:
public class TestClass
{
private Dictionary<Type, Array> _values = new Dictionary<Type, Array>();
}
现在用实际数据填充该集合:
_values.Add(typeof(int?), new int[] { 1, 2, 3 });
_values.Add(typeof(string), new string[] { "a", "b", "c", "d", "e" });
最后是小丑方法:
public T Get<T>(int index)
{
Type type = typeof(T);
Array array;
if (_values.TryGetValue(type, out array))
{
if (index >= 0 && index < array.Length)
{
return (T)array.GetValue(index);
}
}
return default(T);
}
用法:
for (int i = 0; i < 10; i++)
{
int? id = testClass.Get<int?>(i);
string name = testClass.Get<string>(i);
//...
}
答案 2 :(得分:1)
除此之外,你在这里做的事情真的不多:
if (i >= array.Length) return null;
else return array[i];
或使用?
运算符:
return (i >= array.Length) ? null : array[i];
答案 3 :(得分:1)
您可以使用方法而不是属性:
public int? Ids(int i) {
if (i >= 0 && i < _ids.length)
{
return _ids[i];
}
return null;
}
答案 4 :(得分:0)
如果您需要上述情况的快捷方式,我会在您的课程中使用以下方法:
public int? ReadAtOrNull(int index)
{
return index < ids.Lenght && index > 0 ? (int?)ids[index] : null;
}
答案 5 :(得分:0)
请尝试:
for (int i = 0; i < Ids.Length; i++)
{
if (!String.IsNullOrEmpty(testClass.Ids[i].Tostring())
int? id = testClass.Ids[i];
}
答案 6 :(得分:0)
这里的想法似乎是使用类索引。以下是您TestClass
示例的直接答案。
您还可以严格地为内部存储int []的Ids派生自己的自定义集合类,并覆盖所有相应的访问调用,即添加,删除等。(并将这样的集合索引以使其更容易使用)。然后,您的Ids
中可能会有一个名为TestClass
的属性,其行为类似于示例。
我知道这个问题是3个月大,但我希望这仍然有帮助。
public class TestClass {
private int[] ids = new int[] { 1, 2, 3, 4, 5 };
public string Name { get; set; }
public string Description { get; set; }
public int? this[int index] {
get {
if (index < 0 || index > ids.Length - 1)
return null;
return ids[index];
}
set {
if (value == null)
throw new ArgumentNullException(
"this[index]",
"Ids are not nullable"
);
ids[index] = (int)value;
}
}
}
用法:
private void DoSomething() {
TestClass testClass = new TestClass();
for (int i = 0; i < 10; i++) {
int? id = testClass[i];
}
// You can assign to the Ids as well
testClass[0] = 6;
}
答案 7 :(得分:0)
人们可能开始抱怨这可能是一项开销,但是如果您使用Skip
和FirstOrDefault
怎么办?
for (int i = 0; i < 10; i++) //I know I could say i < Ids.Length, its just an example
{
int? id = testClass.Ids.Skip(i).FirstOrDefault();
}
请注意,在这种情况下,您可能需要将数组声明为int?[]
,否则默认值为0
而不是null
。